Helsingin yliopisto / Tietojenkäsittelytieteen laitos / 582309 Ohjelmointitekniikka (Java)
© 2006 Arto Wikla. Tämän oppimateriaalin käyttö on sallittu vain yksityishenkilöille opiskelutarkoituksissa. Materiaalin käyttö muihin tarkoituksiin, kuten kaupallisilla tai muilla kursseilla, on kielletty.

Ohjelmointitekniikka (Java): Harjoituksia jaksolle 1, 16.1.-27.1.

(Viimeisin päivitys 17.1.2006)

Huom: Tehtävät eivät enää muutu, ellei niissä havaita selviä virheitä.

    Poikkeuksista

  1. Try-catch-lausetta voitaisiin käyttää joissakin tilanteissa if-lauseen sijaan, esimerkiksi tyyliin:
    
      if (indeksi kunnossa)          try {
        indeksoi taulukkoa;            indeksoi taulukkoa;
      else                           } 
        hoitele virhe;               catch (indeksointivirhe) {
                                       hoitele virhe;
                                     }
    
    Onko tällaiselle tyylille käyttöä? On väitetty, että poikkeuksen sieppaamisesta generoitava koodi olisi hidasta. Tutki onko näin. Vertaile kokeellisesti if-lauseen ja vastaavan try-catch-lauseen suoritusaikaa. Voiko tulosten perusteella antaa suosituksia ja ohjeita siitä, millasissa tilanteissa poikkeuksia kannattaa käyttää, millaisissa hoitaa virheet toisin? (Samantapaisia asioita pohdittiin syksyn 2005 Java-kurssilla, katso lukua 5.1 Poikkeuksista, erityisesti esimerkkiä ihan sivun lopussa.)
  2. Jos aiheutuneen poikkeuksen tyyppi sopii monen catch-ilmauksen tyyppiin, millä perusteella catch-valitaan? Anna esimerkkejä. Missä mielessä catch-osan valinta muistuttaa kuormitetun metodin valintaa? Missä suhteessa ne eroavat toisistaan?
  3. Jos poikkeuksen tyyppi ei ole yhteensopiva minkään catch-ilmauksen tyypin kanssa, mitä tapahtuu?
  4. Mitä tapahtuu try-lohkossa luodulle oliolle, johon ei ole viitteitä lohkon ulkopuolelta, kun tuossa lohkossa aiheutuu poikkeus?
  5. Mihin finally-lohkoja käytetään ja tarvitaan? Anna esimerkki.
  6. Ohjelmoi yksinkertainen kapseloitu toteutus int-pinolle taulukkoa käyttäen siten, että pinon ylivuoto ja alivuoto (="tyhjästä nyhjäisy") hoidetaan omin poikkeuksin. Anna käyttöesimerkkejä.
  7. Millaisia ominaisuuksia (attribuutteja tms.) poikkeusolioilla on?
  8. Selitä poikkeusluokkien Throwable, Error, Exception ja RuntimeException luokkahierarkia. Mihin näitä käytetään? Mitä ja millaisia ovat "checked"- ja "unchecked"-poikkeukset? Miten ne liittyvät poikkeusten luokkahierarkiaan? Minkä valmiiden poikkeusluokkien aliluokkina omat poikkeusluokat on järkevää toteuttaa? Miksi? Kannattaako omat metodit ohjelmoida heittämään checked- vai unchecked-poikkeuksia? Onko tässä suhteessa erilaisia tilanteita?
  9. Millä tavoin seuraavat tilanteet olisi paras ilmaista operaation kutsujalle. Perustele. Tarkenna tilanteen mahdolliset epämääräisyydet. Huomaa etteivät kaikki tilanteet välttämättä ole "virheitä". (Virheen ilmaisemisen tapoja ovat esimerkikisi poikkeuksen heittäminen, erikoisarvon palauttaminen, yms.)
    1. Linkitetyn Object-listan find-metodi ei löydä haettua Object-oliota.
    2. Linkitetyn int-listan find-metodi ei löydä haettua int-arvoa.
    3. Olioita yksi kerrallaan syöttövirrasta lukeva operaatio yrittää lukea, kun luettavaa ei enää ole.
    4. Jonkin alkeistyypin arvoja yksi kerrallaan syöttövirrasta lukeva operaatio yrittää lukea, kun luettavaa ei enää ole.
    5. Ainoastaan positiivisen int-parametrin sallivalle metodille annetaan negatiivinen arvo.
    6. Ainoastaan positiivisen int-parametrin sallivalle konstruktorille annetaan negatiivinen arvo.
    7. Operaation tehtävänä on luoda olio lukemalla tiedostosta olion kentille arvot. Tiedostossa on jokin virheellinen arvo, jota ei voida vastaavaan kenttään asettaa, eikä ehjää oliota voida siis luoda.
    8. Jollekin tiedostoa käsittelevälle operaatiolle on parametrina annettu tiedosto, jota ei ole olemassa.
    9. Jollekin tiedostoa käsittelevälle operaatiolle on parametrina annettu tiedosto, jolle operaatiolla ei ole käyttöoikeutta.
    10. Operaation yrittäessä avata verkkoyhteyttä johonkin palvelimeen palvelinta ei löydy.
    11. Kesken operaation suorituksen sen tarvitsema viestiliikenteen verkkoyhteys katkeaa.

  10. Tekninen essee: Kirjoita lyhyt (n. 2-3 A4-sivua) ohje poikeusten käyttämisestä Java-ohjelmoinnissa. Alä kirjoita siitä, millaisia ohjelmarakenteita on käytettävä! Kirjoita sen sijaan siitä, millainen toiminta ja menettely on järkevää erilaisissa tilanteissa. Kirjoituksen ajateltu lukija on tietojenkäsittelytieteen aineopintojen loppupuolella oleva opiskelija.


    Geneerisyydestä ja kokoelmista

  11. Olkoon
         Object x;
         Integer y;
         int i;
    
    Selitä miksi seuraavat ovat sallittuja
         x = 1;
         y = 1;
    
         System.out.println(x);
         System.out.println(y);
    
         i = y;
         i = (int)y;
         i = y.intValue();
    
         x = y;
    
    mutta seuraavat virheellisiä:
         i = x;               incompatible types
         i = (int)x;          inconvertible types
         i = x.intValue();    cannot find symbol
    
         y = x;               incompatible types
    
    Miten x:n arvo saadaan asetettua i:lle ja y:lle?

  12. Ohjelmoi yksinkertaisena taulukkototeutuksena geneerinen pino seuraavaan tyyliin:
    public class Pino <T> {
    
      private T[] pino;
      private int huippu;
    
      public Pino()
      ...
      public void push(T alkio)
      ...
      public T pop() 
      ...
      public boolean empty()
      ...
    
    Laadi myös ohjelma, joka esittelee geneerisen pinon käyttöä kokonaislukupinona, merkkijonopinona ja vaikkapa Vector-pinona.

    Taulukko-olion geneerinen luonti ei onnistu seuraavaan tapaan:

    pino = new T[100];
    
    Miksi ei? Mikä mättää? Asia voidaan hoitaa mm. seuraavasti:
    pino = (T[]) new Object[100];
    
    Pohdi miksi? Mistä on kysymys? Kovasti kääntäjä kyllä varoittelee. Mistä ja miksi? Linkkivinkkejä: Java Forums, A. Langer: Arrays in Java Generics

  13. (JS) Näytä pienellä testiohjelmalla havainnollistaen miten rajapintaluokan java.util.Set<E> metodeilla toteutetaan joukko-operaatiot yhdiste, leikkaus ja erotus.

    [Vastauksessa käytettävät metodit: addAll, retainAll, removeAll]

  14. (JS) Pakkauksessa java.util on rajapintaluokka SortedSet<E>, joka laajentaa rajapintaluokkaa Set<E>. Miksi pakkauksessa ei ole rajapintaluokkaa SortedList<E>, joka laajentaisi rajapintaluokkaa List<E>? Miten java.util-pakkauksen rajapintaluokkia olisi muutettava, jos SortedList<E> haluttaisiin mukaan?

    [Vastauksen idea: tavallisessa listassa käyttäjä voi lisätä alkion haluamaansa indeksiin, järjestetyssä listassa tämän ei pitäisi olla mahdollista.]

    Laadi järjestetyn listan toteuttava luokka, joka toteuttaa rajapintaluokan Collection<E>, muttei rajapintaluokkaa List<E>. Luokassa on oltava ainakin parametriton konstruktori sekä konstruktori, jonka parametrina voidaan antaa järjestyksen määrittelevä Comparator<T>-tyyppinen olio. Luokan palauttaman iteraattorin tulee palauttaa listan sisältämät oliot järjestyksessä. Käytä luokan toteutuksessa hyväksesi java.util-pakkauksen valmisluokkia.

  15. (JS) Olioita voidaan järjestää ainakin kahdella eri tavalla: olio voidaan ohjelmoida toteuttamaan rajapinta java.lang.Comparable<T> tai järjestämistä varten voidaan laatia rajapinnan java.util.Comparator<T> toteuttava olio. Millaisissa tilanteissa kannattaisi käyttää mitäkin tapaa ja miksi? Kannattaisiko joskus käyttää kumpaakin tapaa?

    [Mahdollisia pointteja: compareTo-metodeja voi olla vain yksi per olio, Comparator-tyyppisiä oliota taas kuinka monta tahansa. compareTo-metodin toimintaa ei voi muuttaa kesken kaiken (tai voi, muttei saisi...), Comparator-tyyppisen olion taas voi helposti korvata toisella.]

  16. Opiskelijalla on nimi (String), opiskelijanumero (int, nollaa suurempi) ja pisteet (int, arvot 0, ..., 60). Toteuta Opiskelija-luokka normaalein perusaksessorein. Lisäksi sovitaan, että Opiskelija-olioiden samuuden määrää yksin opiskelijanumero, niiden järjestyksen ensisijaisesti nimi, toissijaisesti opiskelijanumero.

    Selvitä itsellesi rajapintaluokkien SortedSet<E> ja Comparator<T>, Comparable<T> sekä luokan TreeSet<E> käyttö joukkojen toteuttamisessa. Myös muuhun kalustoon voit joutua perehtymään.

    Toteuta yksinkertainen sovellus opiskelijatietojen lisäämiseen ja kyselyyn. Tietorakenteena käytetään jotakin joukkoa.

    Selitä millaisia vaatimuksia yhtäsuuruus- ja vertailuoperaatioille on asetettu. Miksi?

  17. Tietokilpailussa sekä kysymykset että vastaukset ovat pelkkiä merkkijonoja. Kaikki kysymykset kysytään ja lopuksi ilmoitetaan oikeiden vastausten ja kaikkien kysymysten lukumäärä.

    Laadi yksinkertainen ohjelma tietokilpailujen toteuttamiseen. Yksi tietokilpailu on yksi kysymys-vastausparien joukko. Sovellus luodaan yksinkertaisesti antamalla nuo parit String-taulukkona konstruktorille, esim:

        String[] kysymykset = (
    
           "Mikä on hauki?",  "Hauki on kala",
           "Kuka on Aku?"  ,  "Ankka",
           ...                                  );
    
        Tietokilpailu visa = new Tietokilpailu(kysymykset);
    
        visa.kysele();
        visa.tulokset();
    
    
    Voit toki hyväksyä oikeiksi vastaukset pienin tai isoin kirjaimin ja muillakin tavoin viritellä ohjelmaa. Oleellista tässä tehtävässä on kuitenkin käyttää toteutustietorakenteena jotakin assosiaatiolistaa. Rajapintaluokka Map<K,V> ja sen toteuttajat voivat olla hyödyllistä luettavaa.

    Mieti ja selitä, miten ohjelma ja sen käyttö muuttuisivat, jos ainoan konstruktorin otsikko olisikin:

    
       public Tietokilpailu(Map<K,V> kysymykset);
    

  18. Tekninen essee: Kirjoita lyhyt (n. 2-3 A4-sivua) yllytyskirjoitus Javan geneeristen kokoelmien käyttämisen iloista ja riemuista. Tarkoitus on vakuuttaa lukija näiden uutuuksien käyttämisen hyödyllisyydestä. Älä keskity liikaa syntaksin yksityiskohtiin tai "kaiken luettelemiseen". Kirjoita sen sijaan yleisellä tasolla siitä, mitä ja millaisia nuo välineet ovat. Hyvin valitut esimerkit ovat toki tarpeen. Kirjoituksen ajateltu lukija on tietojenkäsittelytieteen aineopintojen loppupuolella oleva opiskelija.



[Pääsivulle] Takaisin harjoitusten pääsivulle.