JO, vk2 3.5.1999, tehtävä 4 Tarkastusselostus ja mallivastauksia, Arto Wikla 5.5.99 ======================================================= Tehtävässä piti käyttää annettua luokkaa Syottotiedosto. Harva (n. 2) oli erehtynyt ohjelmoimaan tuota luokkaa. Pisteitä tehtävästä oli jaossa seitsemän. ------------------------------------------------------------------------ Sisältö: Tyypillisiä virheitä Pistejakauma Yksi mahdollinen ratkaisu Toteutus luokalle Syottotiedosto [testitarkoituksiin] ------------------------------------------------------------------------ Tyypillisiä yhden pisteen virheitä: - String[] args-parametria ei tarkisteta; jos komentoriviparametreja ei anneta, args.length == 0. Silloin ei sovi indeksoida. Ja tästä virheestä Syottotiedosto-luokka ei osaa pitää huolta. (Enemmistö oli tehnyt tämän virheen!) - Tiedostojen nimet pyydetään käyttäjältä. - Sovelletaan jotakin metodia arvoon, joka voi olla null. Esim. jotakin "eka.equals(toka)" tai "eka.toCharArray()", kun eka voi olla null. - Toistoehdossa luetaan kahta tiedostoa sivuvaikutuksena ja käytetään silti ehdollista tai-operaatiota ||. Tällöin jälkimmäinen rivi jää lukematta. Esim. while ((ekarivi = eka.lueRivi()) != null || (tokarivi = toka.lueRivi()) != null ) ... lukee vain ekasta, jos sieltä löytyy ei-null. (Tilanteesta riippuen tästä on voinut mennä kaksikin pistettä..., vrt. alla.) - String-arvojen vertailu operaatioin == ja !=. - Pääohjelman kutsuma apumetodi ei ole static. - Tulostetaan otsikko. (Tehtävässä sanottiin: "Ohjelma ei tulosta mitään muuta.") - Sisentelyä ei ole edes yritetty. Tyypillisiä kahden pisteen virheitä: - Joka toinen rivipari hukataan. Esim. jotakin while (eka.lueRivi() != null && toka.lueRivi() != null) { ekarivi = eka.lueRivi(); tokarivi = toka.lueRivi(); ... - Toisistaan poikkeavat rivit tulostetaan moneen kertaan. (Tyypillisesti char[]-taulukkoja for-lauseella vertailtaessa.) - Pidemmän tiedoston lopppurivit jätetään tulostamatta. (Näin voi käydä esim. kun käytetään lukemista sivuvaikutuksena ja ehdollisia loogisia operaatioita (&&, ||) ehdottomien (&, |) sijasta.) Fataaleja virheitä: - Ei luoda Syottotiedosto-olioita. - public class OvatkoSamat extends Syottotiedosto ... ^^^^^^^ Virheitä joista pisteitä ei mennyt: - "=" vertailuoperaationa "==":n sijaan. - Pidemmän tiedoston ensimmäinen "ylimääräinen" rivi jää tulostumatta. (Tästä olisi pitänyt oikeastaan ottaa yksi piste, mutta huomasin asian liian myöhään...) - Puolipisteiden puuttumiset yms. ---------------------------------------------------------------------- Pistejakauma: % 7 4.9 6 11.7 5 15.5 4 17.5 3 9.7 2 4.9 1 7.8 0 28.6 ----------------------------------------------------------------------- Yksi mahdollinen ratkaisu: public class OvatkoSamat { public static void main(String[] args) { if (args.length != 2) { System.out.println("Pitää olla kaksi tiedostoa komentorivillä!"); System.exit(0); } Syottotiedosto eka = new Syottotiedosto(args[0]); Syottotiedosto toka = new Syottotiedosto(args[1]); String ekarivi, tokarivi; while ((ekarivi = eka.lueRivi()) != null | (tokarivi = toka.lueRivi()) != null ) { if (ekarivi != null && tokarivi != null) if (!ekarivi.equals(tokarivi)) { System.out.println("1>" + ekarivi +"<"); System.out.println("2>" + tokarivi +"<"); } if (ekarivi == null) System.out.println("2>" + tokarivi +"<"); if (tokarivi == null) System.out.println("1>" + ekarivi +"<"); } } } --------------------------------------------------------------------- Toteutus luokalle Syottotiedosto [tätä siis ei pitänyt eikä saanut ohjelmoida! Se on tässä jos joku haluaa testata.] public class Syottotiedosto { BufferedReader syotto; Syottotiedosto(String nimi) { try { syotto = new BufferedReader( new InputStreamReader( new FileInputStream(nimi) ) ); } catch (Exception e) { System.out.println("Tiedostoa "+ nimi + " ei löydy."); System.exit(0); } } public String lueRivi() { try { return syotto.readLine(); } catch (Exception e) { System.out.println("Tiedostossa jotain vikaa."); System.exit(0); return null; } } }