From: A Jaakko J Nurro Date: 21.12.2006 14:43:40 ------------------------------------------------------------------------------------ Tehtävästä oli jaossa 14p, jotka kasaantuivat seuraavasti: Komentoriviargumentit käsitellään oikein, eli puuttuminenkin käsitelty siististi: 1p - komentoriviargumentilla/parametrilla tarkoitetaan java-tulkille ajettavan luokkatiedoston nimen jälkeen annettavia parametreja, esim. kun javatulkki käynnistetään komennolla > java Luokka jotain "jotain" on haluttava komentoriviargumentti. Tiedostoa lukeva Scanner luodaan oikein 1p - Scanner-luokan koko nimi on java.util.Scanner. Scannerin importia ei kuitenkaan tarkastettu Tiedoston kanssa tulevat poikkeustilanteet hoidettu oikein, esim. - try tekee jotain järkevää 1p - käytännössä Scannerin luominen tiedostolle voi aiheuttaa tarkistettavan poikkeuksen, se on oleellista käsitellä. Myös komentoriviargumenttitaulukon indeksointia voi kokella try-lauseessa, vaikka siinä mahdollisesti tapahtuvaa poikkeusta ei tarvitsekaan tarkastaa. - catch tekee jotain järkevää 1p - ei ollut järkevää jatkaa niinkuin olisi ollut joku toimiva Scanner-olio, jos poikkeus luonnissa kerran tapahtui tai - väistetään virhetilanne oikein (File.exists()) 1p - throws Exception oikein ja oikeassa paikassa 1p - oikeasti käsiteltävä poikkeus on java.io.FileNotFoundException, mutta kokeessa Exceptionin käsitteleminen riitti Sanaparit luetaan oikein: - talletusrakenne alustetaan oikein 1p - Hashtable-luokan koko nimi on java.util.Hashtable, luokan importia ei kuitenkaan tarkastettu - alkukieliset sanat tulevat rakenteeseen oikein 1p - kohdekieliset sanat tulevat rakenteeseen oikein 1p - uusi käännös jo esiintyvälle alkukieliselle sanalle korvaa vanhan 1p - 'viimeisin käännös jää voimaan' tarkoitti siis viimeisintä tiedostosta löytyvää Sana löytyy oikein: - hakurakenteet, joissa menivät alku- ja kohdekielet sekaisin, eivät saaneet tästä pisteitä - jos löytyy talletusrakenteesta 1p - tieto ettei löydy palautuu jotenkin 1p Näppäimistöä lukeva Scanner luodaan oikein, ja kyselyjen lukeminen hoidetaan oikein 1p Vastaus tulee oikein: - jos käännös löytyy 1p - vaikka käännös ei löytyisi 1p Kyselyjen toisto ja lopettaminen hoidetaan järkevästi 1p Yhteensä 14p Huomioita - Jos ei kirjoittanut javaa, ei yleensä saanut pisteitä siitä kohdasta joka ei ollut javaa. Paljon pikkutypoja katsottiin läpi sormien, kunhan tarkastaja vain pystyi ymmärtämään mitä tekstissä pitäisi lukea. - talletusrakenteena sai käyttää vähän mitä vain, kunhan se toimi kuten yllä ja tehtävänannossa kuvattiin. Esim. tehokkuudella ei ollut väliä, mutta älkää nyt oikeasti etsikö sanan käännöstä suoraan tiedostosta joka haulla, jos vastaavaa jossain oikeasti teette. - lisäksi 10000 sanan raja tulkittiin hyvin monin tavoin. Sekä ratkaisut, joissa sanastotiedostossa sanoja laskettiin olevan yhteensä 10000 että ratkaisut, joissa alkukieli-kohdekieli -sanapareja sai olla 10000 kävivät. - Nenosen Jaakon 2005 esimerkkivastaus hieman samanlaiseen tehtävään oli kopioitu moneen vastaukseen sellaisenaan. Tämä on hyväksyttävää, koska aika suuri osa ohjelmointirutiinista perustuu ratkaisujen tuttuuteen. Yleensä tällaisissa tapauksissa on hyvä selvittää, että on lupa lainata, ja vielä hyvän tavan mukaista kertoa keneltä on lainattu. Tehtävä oli lisäksi osittain erilainen: 2005 versiossa sanastotiedoston nimi pyydetään käyttäjältä syötteenä, 2006 versiossa se halutaan komentoriviparametrina. Kopioi-liimaa -ohjelmointityyli on ajattelematonta ja vaarallista juuri koska silloin voi jäädä korjaamatta kohtia toimimaan vaatimusten mukaisesti. - ohjelman kyselyvaiheen sai lopettaa vähän miten huvitti, vaikka virheeseen. Kyselyä ei edes tarvinnut toistaa, vaikka onhan se vähän hassua ladata iso assosiaatiorakenne täyteen sanastoa, ja sitten tehdä vain yksi haku. Alla kaksiluokkainen esimerkki /* Sanakirja-luokka sisältää sanakirjan toteutuksen ja lataamisen, * kun se on erikseen, voidaan käyttää erilaisia toteutuksia sanakirjalle. */ import java.io.*; import java.util.Scanner; import java.util.Hashtable; public class Sanakirja { // Hashtable on Map-rajapinnan toteuttava assosiaatiotaulukko, // josta voi hakea V luokan olioita käyttäen avaimena K-luokan olioita. // Sanakirja tai puhelinluettelo ovat hyviä vertailukohteita. private Hashtable sanasto; public Sanakirja(String tiedostonnimi) throws FileNotFoundException { // Scannerin luonti tiedostosta voi aiheuttaa poikkeuksen Scanner sanastonlukija = new Scanner(new File(tiedostonnimi)); sanasto = new Hashtable(); while (sanastonlukija.hasNextLine()) { // luetaan tiedostosta alkukielinen sana String alkukielinen = sanastonlukija.nextLine(); // jos tiedostossa on sille pari, luetaan sekin ja talletetaan // sanat assosiaatiotauluun niin että alkukielisen mukaan // voi hakea kohdekielistä if (sanastonlukija.hasNext()) { sanasto.put(alkukielinen, sanastonlukija.nextLine()); } } } /* Palauttaa sanastosta parametrina saatua sanaa vastaavan merkkijonon */ public String kaanna(String sana) { return sanasto.get(sana); } } /* Sanankaannospalvelu-luokka on staattinen käyttöliittymäluokka, joka * käyttää käännöksen apuna Sanakirja-luokan oliota */ import java.util.Scanner; import java.io.FileNotFoundException; public class Sanankaannospalvelu { private static void kaannospalvelu(String tiedostonnimi) throws FileNotFoundException { // sanakirjan luonti voi aiheuttaa poikkeuksen Sanakirja sanakirja = new Sanakirja(tiedostonnimi); Scanner nappaimistonlukija = new Scanner(System.in); // Esimerkkituloste, ctrl-d toimii Unixissa, mutta Windowsissa // se olisi joku muu merkki System.out.println("Syötä sana, jolle haluat kysyä käännöstä."+ "Paina sitten enter.\nSen jälkeen voit kysyä lisää sanoja."+ "Jos haluat lopettaa, syötä vaikkapa ctrl-d"); // käyttäjä voi lopettaa syöttämisen tiedostonloppumerkkin, // jolloin luettavia rivejä ei enää tule nappaimistonlukija-Scannerille while (nappaimistonlukija.hasNextLine()) { String kaannos = sanakirja.kaanna(nappaimistonlukija.nextLine()); // jos sanastosta ei löydy sanaa, kaannos on null, silloin // tulostetaan että alkukielinen sana oli tuntematon // jos kaannos != null, tulostetaan sanastosta löytynyt kaannos System.out.println(kaannos != null? kaannos: "Kysytty alkukielinen sana oli tuntematon."); } } /* Perinteinen pääohjelma, jolla on aliohjelm(i)a. */ public static void main(String [] args) { if (args.length < 1) { System.out.println("Sanakirjatiedoston nimi pääsi unohtumaan."); } else { try { kaannospalvelu(args[0]); } catch(FileNotFoundException fnf) { System.out.println("Sanakirjatiedostoa ei löytynyt."); } } } }