1. OPINTOJAKSON TAVOITTEET, SISÄLTÖ JA ESITIEDOT... 4 2. MATERIAALIT JA OHJELMISTOT... 5



Samankaltaiset tiedostot
1. OPINTOJAKSON TAVOITTEET, SISÄLTÖ JA ESITIEDOT MATERIAALIT JA OHJELMISTOT... 5

Luokkakirjastot. esiintymämetodien käytöstä:

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Standardi- ja tietorakenneluokkia

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

20. Javan omat luokat 20.1

Sisällys. 20. Javan omat luokat. Java API. Pakkaukset. java\lang

Kääreluokat (oppikirjan luku 9.4) (Wrapper-classes)

Vertailulauseet. Ehtolausekkeet. Vertailulauseet. Vertailulauseet. if-lauseke. if-lauseke. Javan perusteet 2004

17. Javan omat luokat 17.1

Java-kielen perusteet

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

Ohjelmoinnin perusteet Y Python

17. Javan omat luokat 17.1

Java-kielen perusteita

16. Javan omat luokat 16.1

2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4)

Ohjelmoinnin jatkokurssi, kurssikoe

Ohjelmoinnin perusteet Y Python

Taulukot. Jukka Harju, Jukka Juslin

Listarakenne (ArrayList-luokka)

812341A Olio-ohjelmointi Peruskäsitteet jatkoa

8. Näppäimistöltä lukeminen 8.1

Metodien tekeminen Javalla

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

Javan perusteet. Ohjelman tehtävät: tietojen syöttö, lukeminen prosessointi, halutun informaation tulostaminen tulostus tiedon varastointi

Tietorakenteet. JAVA-OHJELMOINTI Osa 5: Tietorakenteita. Sisällys. Merkkijonot (String) Luokka String. Metodeja (public)

Tietojen syöttäminen ohjelmalle. Tietojen syöttäminen ohjelmalle Scanner-luokan avulla

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Taulukot & Periytyminen

Rajapinta (interface)

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Ohjelmointi 2 / 2008 Välikoe / Pöytätestaa seuraava ohjelma.

8. Näppäimistöltä lukeminen 8.1

Java kahdessa tunnissa. Jyry Suvilehto

12. Näppäimistöltä lukeminen 12.1

Java-kielen perusteet

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

14. Poikkeukset 14.1

Java-API, rajapinnat, poikkeukset, UML,...

Sisällys. 14. Poikkeukset. Johdanto. Johdanto

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

1 Tehtävän kuvaus ja analysointi

Pakkauksen kokoaminen

Java-kielen perusteet

Sisällys. 14. Poikkeukset. Johdanto. Johdanto

Sisältö. Johdanto. Tiedostojen lukeminen. Tiedostojen kirjoittaminen. 6.2

Ohjelmoinnin perusteet Y Python

Java-kielen perusteita

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Poikkeukset ja tietovirrat: Virhetilanteiden ja syötevirtojen käsittely

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

Olio-ohjelmointi Javalla

14. Poikkeukset 14.1

Tehtävä 1. Tehtävä 2. Arvosteluperusteet Koherentti selitys Koherentti esimerkki

Sisältö Johdanto. Tiedostojen lukeminen. Tiedostojen kirjoittaminen. 26.2

Ohjelmoinnin peruskurssi Y1

Mikä yhteyssuhde on?

7/20: Paketti kasassa ensimmäistä kertaa

Imperatiivisen ohjelmoinnin peruskäsitteet. Meidän käyttämän pseudokielen lauseiden syntaksi

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Tietorakenneluokkia 2: HashMap, TreeMap

1. Omat operaatiot 1.1

ITKP102 Ohjelmointi 1 (6 op)

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

// Tulostetaan double-tyyppiseen muuttujaan "hinta" tallennettu // kertalipun hinta ja vaihdetaan riviä. System.out.printf("%.1f euros.

Sisältö. Johdanto. Tiedostojen lukeminen. Tiedostojen kirjoittaminen. 6.2

Sisältö. 22. Taulukot. Yleistä. Yleistä

Sisällys. 11. Javan toistorakenteet. Laskurimuuttujat. Yleistä

Ehto- ja toistolauseet

A) on käytännöllinen ohjelmointitekniikka. = laajennetaan aikaisemmin tehtyjä luokkia (uudelleenkäytettävyys)

Ohjelmointi 1 / 2009 syksy Tentti / 18.12

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

Sisältö. 2. Taulukot. Yleistä. Yleistä

Informaatioteknologian laitos Olio-ohjelmoinnin perusteet / Salo

C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. Operaatioiden suoritusjärjestys

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

1. OPINTOJAKSON TAVOITTEET, SISÄLTÖ JA ESITIEDOT SUORITUSTAPA... 4

Ohjelmoinnin perusteet Y Python

Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.

Ohjelmoinnin perusteet Y Python

15. Ohjelmoinnin tekniikkaa 15.1

Ohjelmointi 2 / 2010 Välikoe / 26.3

Ohjelmoinnin perusteet Y Python

T Olio-ohjelmointi Osa 5: Periytyminen ja polymorfismi Jukka Jauhiainen OAMK Tekniikan yksikkö 2010

Harjoitustyö: virtuaalikone

Harjoitus 4 (viikko 47)

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Pakkaukset ja määreet

ITKP102 Ohjelmointi 1 (6 op)

1. Olio-ohjelmointi 1.1

Pakkauksen kokoaminen

1.3Lohkorakenne muodostetaan käyttämällä a) puolipistettä b) aaltosulkeita c) BEGIN ja END lausekkeita d) sisennystä

9. Periytyminen Javassa 9.1

11. Javan toistorakenteet 11.1

15. Ohjelmoinnin tekniikkaa 15.1

Ohjelmointi 1 C#, kevät 2013, 2. tentti

Poikkeustenkäsittely

Luokka Murtoluku uudelleen. Kirjoitetaan luokka Murtoluku uudelleen niin, että murtolukujen sieventäminen on mahdollista.

Taulukot. Taulukon käsittely. Tämän osan sisältö. Esimerkki. Taulukon esittely ja luonti. Taulukon alustaminen. Taulukon koko

Harjoitus 5 (viikko 48)

P e d a c o d e ohjelmointikoulutus verkossa

12. Javan toistorakenteet 12.1

812341A Olio-ohjelmointi, Olio-ohjelmoinnin peruskäsitteet ja Java-kieli

Transkriptio:

1. OPINTOJAKSON TAVOITTEET, SISÄLTÖ JA ESITIEDOT... 4 2. MATERIAALIT JA OHJELMISTOT... 5 3. SUORITUSTAVAT... 5 3.1 Tentistä... 5 3.2 Tietokonetyöstä... 6 4. OPISKELUN ETENEMINEN... 6 VIIKKO 3... 8 Luokka Object. Kirjastoluokkia osa I: String, StringBuffer, StringBuilder, StringTokenizer, DecimalFormat, Math ja Random. Pakkaukset ja import-lause.... 8 Alustus 8 equals-metodi olioiden yhteydessä 14 Luokat StringBuffer ja StringBuilder 15 Luokka StringTokenizer ja luokan String metodi split 18 Tulostuksen muotoilu ja DecimalFormat 20 Merkkijonon ja tekstitiedoston läpikäynti käyttäen luokkaa Scanner 20 Random 22 Luokakirjastojen toteutukset 23 Harjoitustehtävät... 24 VIIKKO 4... 25 Kirjastoluokkia osa II: Integer (ja muut kuori- eli kääreluokat). Dynaamiset geneeriset listat: luokat Vector, ArrayList ja LinkedList. Automaattiset tyypinmuunnokset kuoriluokkien ja vastaavien perustyyppien välillä. for-each rakenne ja iteraattorit. Luokat Arrays ja Collections.... 25 Integer 25 Tyypinmuunnokset sekä autoboxing ja unboxing 27 Johdanto dynaamisiin listoihin (oliokokoelmat) ja geneerisyyteen 29 Java 5.0:sta lähtien: Geneeriset luokat Vector <E>, ArrayList<E> ja LinkedList<E> 31 Esimerkki: Lisäyslajittelu 37 Taulukoiden ja listojen läpikäynti käyttäen for-each lausetta (Java 5.0:sta lähtien) ja iteraattoria 39 Luokat Arrays ja Collections staattisten ja dynaamisten listojen käsittelyyn (mm. lajittelu käyttäen kirjastometodia sort) 41 Harjoitustehtävät... 42 VIIKKO 5... 43 Olio-ohjelmoinnin peruskäsitteet: oliot ja luokat, olioiden tietosisältö ja käyttäytyminen, luokan määrittely, olioiden luonti ja käsittely.... 43 Alustus 43 Johdatus: tietueen käsitteestä luokan käsitteeseen käyttäen esimerkkinä henkilötietoja 44 Luokan Henkilo oikeaoppinen määrittely sekä this ja tostring 50 Harjoitustehtävät... 53 1

VIIKKO 6... 55 Oman tietotyypin määrittely luokan avulla: Olio-ohjelmointiin liittyvät käsitteet ja niiden ilmaiseminen Javassa... 55 Alustus 55 Tietotyypin määrittely 56 Luokan tietokentät: esiintymämuuttuja / luokkamuuttuja tai -vakio 57 Luokassa määritellyt metodit: esiintymämetodi / luokkametodi 57 Näkyvyys 58 Kuinka luokan tietokenttiin ja metodeihin voidaan viitata 58 Käytännön ohjeita: main-metodin sisältävä luokka vs. muut luokat 60 Yhteenveto sopivista tietotyypin tietokenttien ja metodien määreistä, kun noudatamme kapselointiperiaatetta 61 Harjoitustehtävät... 62 VIIKKO 7... 63 Olio-ohjelmien suunnittelu, oliot koostuvat olioista, sisäluokka.... 63 Olio-ohjelmoinnin idea lyhyesti 63 Tunnuksien nimeämiskäytäntö 63 Miksi tietosisältö pitäisi kätkeä? 64 Olioiden koostuminen olioista 64 Sisäluokka 65 Harjoitustehtävät... 66 VIIKKO 9... 70 Periytyminen ja luokkahierarkia, abstrakti metodi ja luokka, rajapintaluokka ja Comparable<T>. Tietokonetyön valinta.... 70 Alustus periytymisestä ja luokkahierarkiasta 70 Luokat Employee ja Boss 71 Polymorfismi ja dynaaminen sidonta 73 Abstrakti luokka ja metodi (abstract class and method) 74 Rajapintaluokka (Interface class) 77 Rajapintaluokka Comparable<T> 79 Harjoitustehtävät... 82 Tietokonetyön valinta... 83 LUENTOPÄIVÄ 5.3.2016... 84 Joitakin Javan valmiita luokkia... 84 Olio-ohjelmoinnin periaatteita... 85 Kokoava esimerkki... 85 Luokka Tili 86 Luokka Pankki ja sen testaus 89 Perintä: Luokan Tili aliluokka ShekkiTili, staattinen ja dynaaminen tyyppi 96 Tehtäviä... 101 2

VIIKKO 10... 103 Poikkeukset. Määre final. Graafiset käyttöliittymät (GUI). Tietokonetyö.... 103 Alustus 103 Poikkeukset Javassa 104 Javan poikkeusluokat 105 try catch lause 106 Esimerkki poikkeusten käsittelystä: metodi lueint luokkaa Scanner käyttäen 107 Määre final: sen merkitys eri tilanteissa 108 Harjoitustehtävät... 109 VIIKKO 11... 110 Tietokonetyö, hajautustaulu: luokka HashMap<K,V>... 110 Tietokonetyö 110 Luokka HashMap 110 Harjoitustehtävät... 113 Liite 1 ja 2. Kurssisivuilla. 3

1. OPINTOJAKSON TAVOITTEET, SISÄLTÖ JA ESITIEDOT Opintojaksolla laajennetaan opintojaksolla Algoritmien ja ohjelmoinnin peruskurssi (AOP) annettua kuvaa ohjelmoinnista tutustumalla olio-ohjelmointiin. Kurssin jälkeen opiskelija tuntee olio-ohjelmointikielten käsitteet ja osaa käyttää Javan luokkakirjastoa (esim. merkkijonojen käsittelyyn ja dynaamisten listojen suunnitellut luokat). Opiskelija osaa tehdä olio-ohjelmia, määritellä luokkien avulla omia tietotyyppejä sekä hyödyntää myös perintää ja tuntee poikkeusten käsittelyn perusteet. Keskeisin sisältö on kuitenkin omien tietotyyppien määrittelemisessä. Kurssilla opetetaan myös perintä ja siihen liittyvät käsitteet sekä johdannonomaisesti poikkeukset. Tavoitteena on antaa olio-ohjelmoinnista sellainen kuva, jonka perusteella muiden (olio-)ohjelmointikielten opiskelu sujuu muitta mutkitta. Olio-ohjelmoinnin opiskelussa voidaan edetä joko menemällä heti luokkien ja olioiden maailmaan tai unohtamalla aluksi oliot tarkastelemalla ensin perinteellistä ohjelmointia, jossa käsitellään vain primitiivistä tietoa (perustyypit, esim. luvut). Tällä opintokokonaisuudella noudatetaan jälkimmäistä lähestymistapaa, koska tällöin ei tarvitse haukata koko kakkua yhdellä kertaa. Nimittäin olio-ohjelmoinnissa tarvitaan myös kaikki perinteellisen ohjelmoinnin välineet: algoritmeja ohjataan peräkkäis-, valinta- ja toistorakenteilla tallettamalla arvoja muistipaikkoihin, joita käsiteltiin jaksolla AOP. Esimerkiksi tehtävissä laske syötettyjen lukujen keskiarvo ja tutki onko annettu luku alkuluku ei ole juurikaan sijaa olioille. Tämän jälkeen huomaamme, että maailma ei koostu pelkästään luvuista ja merkeistä, vaan että asioiden mallinnus tapahtuu paljon korkeammalla tasolla. Tarvitsemme siis keinon, millä voimme esittää, mallintaa (abstrahointi) ja käsitellä suurempia tietoja yhtenä kokonaisuutena. Tähän tarpeeseen vastaa abstraktin tietotyypin (ADT) käsite, joka olio-ohjelmoinnissa toteutetaan luokkana. Näin ollen tällä opintojaksolla Olio-ohjelmoinnin perusteet (OOP) siirrymme motivoidusti olioohjelmoinnin peruskäsitteisiin: luokka ja olio. Esitiedot: Tämän opintojakson esitietoina vaaditaan opintojakson Algoritmien ja ohjelmoinnin peruskurssi (AOP) tiedot. Jakso OOP jatkaa siitä, mihin jaksolla AOP jäätiin. Tällä jaksolla oletetaan, että Javan peruskontrollirakenteet, perustyypit, oliotyypit, taulukot, luokan String ja Random käsittely hallitaan, joskin tällä jaksolla syvennetään luokkien String ja Random ominaisuuksia. 4

2. MATERIAALIT JA OHJELMISTOT Opintojaksolla ei ole käytössä opintomonistetta, vaan päämateriaali on tämä opiskeluopas ja sen lisäksi harjoitustehtävät ja niiden malliratkaisut, jotka ovat usein laajoja. jakson Algoritmien ja ohjelmoinnin peruskurssin opintomonisteen tiettyjä osia käsitellään tällä kurssilla uudestaan perusteellisemmin. Liite 1, joka on kurssisivuilla (se on ote Ville Leppäsen opintomonisteesta Ohjelmointi I). Liite 1 sisältää viittauksia kohtiin, joita liitteessä ei ole, mutta nämä eivät ole oleellisia tämän kurssin kannalta. Liite 2, joka on kurssisivuilla (se on ote kirjasta Simo Silander, Vesa Ollikainen, Juha Peltomäki: Java, ISBN: 978-951-0-36081-1. Julkaistu: 03/2010, Sivuja: 498 (ks. kurssisivut). Kurssisivuille tulee kurssin edetessä lisämateriaalia, joista osa vaaditaan myös tentissä. Vaadittavat osat on merkitty selvästi kurssisivuilla. Kurssisivuilla on useita linkkejä, joita voi käyttää opiskelun apuna. Java-ohjelmointiympäristönä olisi hyvä käyttää JCreatoria tai jotain muuta kehittyneempää ympäristöä, esim. NetBeans. Esim. JCreatorin avulla voidaan havainnollistaa luokan rakennetta käyttäen Class View näkymää: tietokentät ja metodit näkyvät omassa ikkunassaan eri värisinä. Myös NetBeans (Members view) ja Eclipse näyttävät nämä ja vieläpä tarkemmin. Myös DrJavaa voi käyttää, joskin siinä ei ole edellä mainittuja ominaisuuksia. 3. SUORITUSTAVAT Opintojaksoon kuuluu tentti ja yksi tietokoneella tehtävä tietokonetyö. 3.1 Tentistä Tenttioikeuden saa jos on tehnyt hyväksytysti vähintään 30% tehtävistä. Tentin läpäisemiseen vaaditaan n. 50 % maksimipistemäärästä. Tentissä on myös ns. essee-kysymyksiä, jossa ei ole tärkeintä pelkästään muistaa kaikki aiheeseen liittyvät asiat, vaan ymmärtää ne, ja esittää ne jäsentyneesti. Essee-kysymyksessä pyydetään pääasiassa selittämään tiettyjä käsitteitä/asioita tai Javan tiettyjen tärkeiden avainsanojen merkitys. Kysytyt ohjelmointitehtävät ovat hyvin paljon tässä opiskeluoppaassa esitettyjen esimerkkien ja tehtävien kaltaisia. Tenttiin kannattaa valmistautua lukemalla erityisesti oppimateriaalin esimerkit ja harjoitustehtävät. 5

Huomaa, että ohjelmien teko tentissä melko lyhyessä ajassa ei kerta kaikkiaan onnistu, ellei omaa minkäänlaista ohjelmointirutiinia. Sen vuoksi tenttiin valmistautuessa kannattaa yrittää ratkaista harjoitustehtäviä uudestaan katsomatta valmista ratkaisua, testata niitä koneella ja tutkia tarkasti niiden toimintaa eikä pelkästään lukea valmiita ohjelmia. Valmiin ohjelman ymmärtäminen ei vielä takaa sitä, että pystyisi itse tuottamaan vastaavan toimivan ohjelman; ei, kaukana siitä. Ohjelmien toiminnassa ei ole mitään selittämätöntä, vaan jokaisen lauseen suoritus muuttaa ohjelman tilaa (eli ohjelmien muuttujien arvoja) lauseen toiminnan määräämällä tavalla edeten ohjelman ensimmäisestä lauseesta aina viimeiseen lauseeseen saakka. Yritä aina ymmärtää jokaisen lauseen suorituksen aiheuttama muutos ohjelman tilaan (eli muuttujien arvoihin). Tentissä annetaan lainaksi joitakin Javan kirjastoluokkien kuvauksia. Ne ovat myös kurssisivuilla, joten tutustu niihin etukäteen. Tenttipäivät: Ensimmäinen on torstaina 24.3.2016. Muut ilmoitetaan kurssisivuillamme. Huom. Jakso AOP tulee olla suoritettu kokonaisuudessaan ennen kun voi tenttiä OOPin. Jakson OOP tietokonetyön suunnitelma tulee palauttaa sähköpostitse ennen tenttiä ja olisi hyvä jos koodikin olisi lähes valmis. Katso kurssisivuilla esitetyt vaatimukset tenttien suhteen. 3.2 Tietokonetyöstä Tehtävän määrittelyt ja viimeinen palautuspäivämäärä kerrotaan kurssisivuilla linkin Tiekonetyö takana. Huomaa, että voitte itse valita työn yksin tai pareittain. Työstä tehdään ensin suunnitelma, jonka muoto kerrotaan kurssisivuilla ja esimerkki suunnitelmasta on s. 66 Murtoluku-tehtävässä. Töitä ohjataan kuten kurssisivuilla kerrotaan. Saat palautteen työstäsi sähköpostitse. Huomaa, että luentopäivällä käsiteltävä pankkisovellus on hyvä lähtökohta tietokonetyölle. Työn nopeata tekemistä kannustetaan antamalla myös ylimääräisiä bonuksia (katso kahden viimeisen viikon Harjoitustehtävät). 4. OPISKELUN ETENEMINEN Opintoryhmäkokoontumisten lisäksi järjestetään yksi lähiopetustilaisuus, jolloin yliopiston opettaja kertaa siihen mennessä käsitellyistä asioista tärkeimmät. Lisäksi tällöin opiskelijoilla on mahdollisuus kysyä opintojakson epäselviksi jääneistä kohdista. Opiskelu perustuu itseopiskeluun opiskeluoppaan avustamana, viikoittaisten harjoitustehtävien itsenäiseen laatimiseen ja niistä annettavaan palautteeseen. Lisäksi Moodlessa annetaan vinkkejä tehtävien tekemiseen ja siellä voi myös keskustella tehtävistä. Harjoitustehtävät on jaettu aiheen perusteella kullekin viikolle niin, että ne kattavat viikon asiat. Harjoitustehtävien huolellinen läpikäynti on opiskelun keskeisin osa. Koska opintoryhmäkokoontumisten sisältö on aina hyvin samantapainen, ei niiden sisältöä ole aina esitetty ohjelman yhteydessä. Opintoryhmäkokoontumisen yhteydessä käsitellään viikolle tarkoitetut harjoitustehtävät joiden yhteydessä varmistetaan, että viikon asiat ja tässä oppaassa esitetyt esimerkit on ymmärretty. Tällöin opiskelijan tulee olla itse aktiivinen ja kysyä viikon epäselvistä asioista ja esimerkeistä. 6

Ryhmäkokoontumisissa tuutori jakaa vastuuopettajan laatimat harjoitustehtävien mallivastaukset ja ne tulevat myös Moodleen takautuvasti. Mikäli opintoryhmäkokoontumisiin on suunniteltu jotakin muuta edellisen lisäksi, on siitä maininta viikoittaisen ohjelman kuvauksen yhteydessä. Ohjelmoinnin oppimisessa ei voi liikaa korostaa itsenäisen opiskelun osuutta. Viikolle merkittyjen harjoitustehtävien miettiminen, tekeminen ja koneella suorittaminen on todella tärkeätä. Laskemalla suoraan opintojakson laajuus opintopisteinä ja sen kesto, niin voimme arvioida, että opiskelijan tulisi käyttää tämän opintojakson opiskeluun keskimäärin n. 14 tuntia viikossa (ryhmäkokoontuminen mukaan lukien) ja kokemuksieni mukaan tämä on aika oikeaan osuva arvio. Tämä arvio edellyttää sen, että jakson AOP asiat ovat hallinnassa. On tietenkin selvää, että arvioitu tuntimäärä vaihtelee hyvinkin paljon riippuen opiskelijasta. Huomaa taas, että käsitteet ovat hyvin tärkeitä. Ne tarkoittavat tarkasti määriteltyä asiaa tai ominaisuutta. AOP:ssa meillä oli jo mm. seuraavia käsitteitä: muuttuja, tyyppi, perus- eli primitiivityyppi, olio- eli viittaus- eli viitetyyppi), lause, lauseke, lausekelause, toistolause, valintalause, metodi, muodollinen parametri, todellinen parametri, esiintymämetodi, luokkametodi (eli staattinen metodi). Tällä kurssilla oletetaan että yo. käsitteet hallitaan. Sinun kannattaa tehdä itsellesi käsiteluettelo, johon kirjaat aina vastaantulevat uudet käsitteet. Ohjelmointia opeteltaessa on erittäin tärkeätä testata ohjelmia koneella. Pelkällä ohjelmien lukemisella ei opi ohjelmoimaan. Sen vuoksi sinun kannattaakin kirjoittaa ohjelmia koneella, muuttaa niitä usealla eri tavalla ja katsoa mitä muutoksesi saa aikaan. Tällöin on kuitenkin erityisen tärkeätä se, että ymmärrät miten ohjelma toimii. Huom. Viikolla 8 ei ole ohjelmaa lainkaan. 7

VIIKKO 3 Luokka Object. Kirjastoluokkia osa I: String, StringBuffer, StringBuilder, StringTokenizer, DecimalFormat, Math ja Random. Pakkaukset ja import-lause. Alustus Jaksolla AOP luokat sisälsivät vain metodeja ja luokissa oli aina main-metodi. Tällöin luokilla ei mallinnettu tietotyyppejä eli tarkastelimme tällöin 'perinteellisiä' ohjelmia. Tämän ja seuraavan viikon tärkeä tavoite on valaista ja tutustuttaa valmiiden luokkien Javan luokkakirjaston käyttöön. Kuten muistanette, luokkakirjaston (API eli Application Programming Interface) käyttö on keskeinen osa olio-ohjelmointia. Seuraavassa sanomme kaikkien valmiina olevien luokkien (joita voimme siis käyttää suoraan omissa ohjelmissamme) joukkoa siis luokkakirjastoksi ja sen yksittäistä luokkaa (esim. String) kirjastoluokaksi. Viikkoina 3 ja 4 käsittelemme luokkia, joissa on main-metodi ja luokat eivät vielä määrittele omia tietotyyppejä. Sen sijaan viikkojen 3 ja 4 jälkeen käsitellään olio-ohjelmoinnin peruskäsitteet (näitä asioita ja käsitteitä tulee tietenkin esille jo viikoilla 3 ja 4) ja määrittelemme itse luokkia, jotka mallintavat tiettyjä asioita ja määrittelevät tietotyypin (eivätkä sisällä mainmetodia). Tämän viikon materiaali on suoraa jatkoa jakson AOPin viimeiselle viikolle ja tässä esitetään kertauksena useita jakson AOP asioita. Kertaa siis aluksi jakson AOP viimeisen viikon sisältö. Perus- ja oliotyyppisen muuttujan ero ja asetuslauseen toiminta tulee myös kerrata lukemalla AOP-opintomonisteen luku 2.5.1. Edellisellä kurssilla meillä oli käytössä luokan String lyhennetty kuvaus. Niin nytkin, mutta tällä kurssilla keskeisenä kuvauksien lähteinä ovat java-kansioissa (hakemistoissa) olevat englanninkieliset kuvaukset, joiden tiivistelmä on käytössä myös tentissä. Jaksolla AOP kerrottiin, että Javassa muuttujat ovat joko perustyyppisiä (esim. int) tai viittauseli oliotyyppisiä (esim. taulukot, String ja itse tehtyjen luokkien mukaiset oliot). On hyvä huomata, että vaikka taulukot ovat oliotyyppisiä, niin niiden käsittely ei ole samanlaista kuin muiden olioiden käsittely. Nimittäin taulukko-olioiden sisällön tarkastelemiseksi tai muuttamiseksi ei tarvitse käyttää mitään tiettyä metodia, vaan taulukon komponentteihin viitataan Javassa (perinteellisesti) hakasuljenotaatiolla; esim. vek[2]. Näin ollen taulukoiden käsittely ei näytä siltä, että ne olisivat olioita, joskin new:n käyttö taulukkoa luotaessa paljastaa, että kyseessä on olio. Myös luokan String-olioille voidaan suorittaa operaatioita, jotka eivät noudata yleisiä olion käsittelyperiaatteita: oliota voidaan käsitellä vain ko. luokan metodien avulla. Esimerkiksi vakiomerkkijono voidaan luoda ilman new:tä ja luokan konstruktoria; esim. String st= java ; 8

Lisäksi String-tyyppisiä merkkijonoja voidaan liittää peräkkäin eli katenoida käyttäen + operaattoria. Lisäksi voimme muodostaa lausekkeita, joissa on sekaisin lukutyyppisiä ja Stringtyyppisiä arvoja, jolloin tuloksena on String-tyyppinen olio. Näin olemme jo tehneet tulostuslauseissa, mutta niin voidaan menetellä muuallakin: voimme esim. kirjoittaa 1 : String st =1.5+ 333 + y ; jossa yhdistetään kolme erityyppistä (double, String, char) arvoa. Tuloksena on String-olio 1.5333y. Yhdistyksen tyypinmuunnoksien ehtona on se, että lausekkeessa tulee olla mukana vähintään yksi String-tyyppinen lauseke ja tämähän saadaan helposti aikaan liittämällä lausekkeeseen tarvittaessa tyhjä merkkijono (kaksi lainausmerkkiä peräkkäin). Kaikki nämä temput ovat kiellettyjä muiden oliotyyppien (esim. StringBuffer) yhteydessä. Taulukoiden ja osin myös merkkijonojen käsittely ovat kielikohtaisia eivätkä tue aina yleisiä olio-ohjelmoinnin periaatteita. Sen sijaan kaikkia muita oliotyyppisiä muuttujia käsitellään aina luokan metodien avulla ja metodin kutsu kohdistetaan ko. luokan mukaiseen olioon käyttäen pistenotaatiota: esim. st.charat(2), missä st on String-tyyppinen muuttuja (olio) ja charat on kirjastoluokan String metodi. Kyseinen lauseke palauttaa merkkijonon st kohdassa 2 olevan merkin. Ensiksi olio täytyy kuitenkin luoda 1) käyttäen new-lauseketta tai 2) luokan Stringoliota luotaessa suoraan asetuslauseella käyttämättä new-lauseketta. Javaan kuuluu lukuisa määrä valmiita kirjastoluokkia, jotka ovat ohjelmoijan käytettävissä. Jaksolla AOP käsiteltiin jo luokkia String, Random ja Math (kertaa nämä asiat jakson AOP opintomonisteesta ja opiskeluoppaasta) ja tällä viikolla keskitytään näiden lisäksi kirjastoluokkiin StringBuffer, StringBuilder ja StringTokenizer, joiden avulla voidaan käsitellä merkkijonoja (tekstiä). On tärkeätä ymmärtää, että jokainen kirjastoluokka (poislukien metodikirjastot, esim. Math) määrittelee tietotyypin. Kyseessä on jonkin abstraktin tietotyypin valmis implementointi Javan luokan avulla. Esimerkiksi merkkijonojen käsittelyyn on useita erilaisia tietotyyppejä, jotka tarjoavat erilaisia ja eri tavalla implementoituja työkaluja (metodeja) merkkijonojen käsittelyyn. Kaikkien luokkien yliluokka on Object. Se sisältää useita metodeja, jotka kuitenkin ovat usein uudelleenmääriteltyjä sen aliluokissa (esim. luokassa String), koska luokan Object metodit ovat usein liian yleisiä ja eivät sovellu suoraan aliluokkaan sellaisenaan. Jokainen Javan luokka (siis myös meidän itse määrittelemät tietotyypit) perii 2 automaattisesti luokan Object kaikki metodit. Perintä tarkoittaa sitä, että aliluokka saa käyttöönsä perittävän luokan määrittelemiä toiminnallisuuksia ja ominaisuuksia. Luokka Object sisältää muun muassa metodin tostring, joka palauttaa olion merkkijonoesityksen. Näin ollen se periytyy kaikkiin luokkiin. Kuitenkin sen tuottama merkkijono on usein aika kelvoton ja siksi se määritellään aliluokassa uudelleen niin, että se tuottaa aliluokalle sopivan merkkijonon. Tästä saadaan esimerkkejä jo tällä viikolla ja myös itse määrittelemämme tietotyypin Henkilo yhteydessä. 1 Tämä näyttää aivan järjettömältä! 2 Luokkahierarkiaan ja luokkien väliseen perintään palataan myöhemmin tarkemmin. 9

Opiskeluohje: Liite 1 sisältää näiden tietotyyppien ja niiden tärkeimpien metodien kuvaukset. Lue ensin alla oleva alla ja sen jälkeen Liitteen 1 s. 87-94 (voit lukea niitä myös rinnakkain), mutta huomaa, että metodien kuvaukset ovat Liitteessä 1. Luokan String metodien vahvasti yksinkertaistettu kuvaus on jakson AOP opintomonisteessa, mutta kaikkien luokkien täydellinen kuvaus löytyy koneessasi (ja netissä) olevien kirjastoluokkien kuvauksista. Pakkaus (package) on Javan väline esittää jollain tavalla yhteenkuuluvat luokat (tai oikeastaan niitä vastaavat class-tiedostot) kokonaisuutena. Tämä esitetään kirjoittamalla luokan alkuun package-määre. Pakkaus ei liity olio-ohjelmointiin, vaan se on käytännön ohjelmistotuotannon väline. Omien pakkausten määrittely ja käyttö eivät kuulu tämän kurssin vaatimuksiin. Yksinkertaisimmillaan pakkaus on hakemisto, johon luokat on sijoitettu. Tietyn pakkauksen saa käyttöönsä missä luokassa tahansa kirjoittamalla luokkaan import-lauseen. Myös valmisluokat on koottu pakkauksiksi. Toisia valmisluokkia voidaan käyttää suoraan ilman mitään erityisiä toimenpiteitä (nämä luokat kuuluvat pakkaukseen java.lang 3 ), kun taas toisten valmisluokkien käyttö vaatii import -lauseen, joka kirjoitetaan ennen sen luokan määrittelyä, jossa kirjastoluokkaa käytetään. Ensiksi mainittuja luokkia edustaa mm. luokat String, StringBuffer, Math ja Integer. Sen sijaan luokan Random käyttö vaatii import-lauseen: import java.util.random; ja luokan StringTokenizer käyttö vaatii import-lauseen 4 : import java.util.stringtokenizer; tai import java.util.*; jolloin saa käyttöönsä kummankin ja paljon muutakin eli kaikki pakkauksen java.util luokat. *:n käyttö ei vaikuta ohjelman tehokkuuteen tai kokoon eli kaikki luokkia ei ladata. Pakkaukset java.util ja java.lang ovat pakkauksen java alipakkauksia. Jos tiedoston alussa ei ole package-määrettä, class-tiedostot asetetaan nimettömään pakkaukseen. Se on Java-toteutuksissa nykyhakemisto, so. hakemisto, jossa class-tiedosto sijaitsee. Tällöin ohjelmoija voi käyttää luokassa vain tässä hakemistossa olevia luokkia. Lisätietoja ja esimerkkejä pakkauksista on mm. kursssivujen kohdassa Muita hyödyllisiä linkkejä". Luokan esiintymä eli olio luodaan kirjoittamalla: new <konstruktorin kutsu>; missä konstruktorin nimi on aina sama kuin luokan nimi. Mahdolliset konstruktorimetodit esitetään luokkakirjastossa ja huomaa, että niitä on yleensä useita (metodin ylikuormitus!) ja että ne ovat usein parametrisoitu. Katso String-olioiden luontiesimerkkejä jaksolta AOP. Luokkakirjastossa luokkien kuvauksessa on annettu luokan tietokenttien (Field Summary), konstruktorien (Constuctor Summary) ja metodien (Method Summary) kuvaukset. 3 Jos installoit Javan dokumentaation, näiden luokkien kuvaukset löytyvät koneesi java-kansion alta kansiosta..\docs\api\java\lang tai netistä. Luokkien kuvaukset ovat html-tiedostoja, jotka voi avata kaksoisklikkaamalla. 4 Näiden luokkien kuvaukset löytyvät taas kansiosta..\docs\api\java\util 10

Tietokenttien ja metodien kuvauksessa voi olla määre static, jolloin se on ns. luokkamuuttuja tai luokkametodi 5. Näitä käytetään muodossa <luokan nimi>.<kentän nimi tai metodi kutsu> Tällöin ei luoda luokan oliota, vaan metodia käytetään perinteellisen aliohjelman tavoin. Jos taas kuvauksessa ei ole määrettä static, niin kyseessä on ns. esiintymämetodi, joita käytetään muodossa <olio>.<metodin kutsu> Näistä puhutaan lisää myös seuraavan esimerkin yhteydessä. Olioita käsitellään kohdistamalla olioon luokan metodin kutsu edellä mainitulla tavalla (poikkeuksena taulukoiden käsittely ja String-olioiden jotkut toiminnot) ja sen vuoksi esiintymämetodeja sanotaan myös olioiden metodeiksi (kuten Liitteessä 1). Terminologia vaihtelee jonkun verran eri lähteissä. Tässä oppaassa puhutaan aina esiintymämuuttujista ja esiintymämetodeista, mutta muualla saattaa termin esiintymä tilalla olla ilmentymä tai instanssi (vastaava eng. kielinen termi on instance) eli voidaan puhua esim. ilmentymämetodista. Huomaa siis, että ominaisuus: "onko kuvauksessa määre static tai ei ole" määrää sen onko kyseessä luokka- vai esiintymämetodi, joka määrää taas sen miten metodia käytetään (kutsutaan). Huom. Liitteessä 1 on vain osa luokkien kuvauksista ja ne eivät siis sisällä kaikkia luokkien metodeja. Opettele siis heti lukemaan tietokoneessasi olevia kirjastoluokkien kuvauksia. Kun luet alla olevaa, niin katso luokkakirjastosta käytetyn konstruktorin tai metodin kuvaus. Aloitamme yksinkertaisilla AOP-kurssin tasoisilla esimerkeillä, jotka käsittelevät luokkaa String. 5 Sanan luokka käyttö tässä yhteydessä (esim. luokkamuuttuja) viittaa siihen, että ko. asiaa käytetään ilman luokan oliota. Sen sijaan sana esiintymä (esim. esiintymämetodi), viittaa siihen että, ko. asiaa voidaan käyttää vain luokan olion esiintymän kanssa. Myöhemmin kun määrittelemme omia tietotyyppejä, otamme käyttöön myös termin esiintymämuuttuja. 11

Esimerkki. Tehdään ohjelma, joka tulostaa annetun merkin esiintymien sijainnit annetussa merkkijonossa. Merkkijono luetaan String-tyyppiseen muuttujaan kohde ja tarkasteltava merkki char-tyyppiseen muuttujaan c käyttäen luokkaa OmaIO. Merkkijono kohde käydään läpi merkeittäin silmukassa. Esimerkiksi jos kohde= java ja c= a, niin sijainnit ovat 1 ja 3. public class FindPositions /** Tulostetaan annetun merkin esiintymät annetussa merkkijonossa. */ public static void main(string[] args) System.out.println("Anna merkkijono"); String kohde = OmaIO.lueString( ); System.out.println("Anna etsittava merkki "); char c = OmaIO.lueChar( ); System.out.println("Etsitaan merkin " + c + esiintymat merkkijonosta " + kohde); for (int i=0; i<kohde.length( ); i++) if (kohde.charat(i)==c) System.out.println("Loytyi kohdasta " + i + "."); // if // for // main // class FindPositions Edellä for-lauseen runko ja if-lauseen then-haara koostuvat vain yhdestä lauseesta, joten niiden ympärillä ei tarvittaisi lausesulkuja ja. Yllä charat on luokan String esiintymämetodi ja sen ulkoinen kuvaus luokkakirjastossa (APIdokumentointi ) http://docs.oracle.com/javase/8/docs/api/ on: char charat(int index) Returns the char value at the specified index. Vasemmalla on metodin tulostyyppi, joka on tässä char. Koska tässä ei ole sanaa static ennen tyyppiä char, niin kyseessä on esiintymämetodi. Näin ollen metodin kutsu kohdistetaan aina luokan String-olioon ja näin ollen lausekkeen kohde.charat(i) arvo on tyyppiä char. Metodin nimi on siis charat ja sillä on yksi int-tyyppinen parametri, jolla viitataan merkkijonon tiettyyn positioon ja tässäkin merkkijonon indeksointi alkaa nollasta. Klikkaamalla metodin nimeä saa näkyviin tarkemman kuvauksen metodista (tässä tapauksessa lyhyt kuvaus on kuitenkin riittävä): 12

public char charat(int index) Metodin otsikkorivi Returns the char value at the specified index. An index ranges from 0 to length() - 1. The first char value of the sequence is at index 0, the next at index 1, and so on, as for array indexing. If the char value specified by the index is a surrogate, the surrogate value is returned. Specified by: Parameters: Returns: Throws: charat in interface CharSequence (CharSequence on interface eli rajapintaluokka, käsitellään myöhemmin) index - the index of the char value. the char value at the specified index of this string. The first char value is at index 0. IndexOutOfBoundsException - if the index argument is negative or not less than the length of this string. Nostaa poikkeuksen eli virheen (käsitellään myöhemmin), jos index<0 tai index>=kohdemerkkijonon pituus. Seuraavassa on vielä ratkaisu, jossa lukemiseen ei käytetä itsetehtyä luokkaa OmaIO, vaan Javan versiosta 5.0:sta lähtien 6 mukana olevaa kirjastoluokkaa Scanner. Luokkaa Scanner on käsitelty tarkemmin edellisellä kurssin AOP opiskeluoppaan liitteessä ja se löytyy myös OOPin sivuilta. import java.util.scanner; public class FindPositions2 /* Tulostetaan annetun merkin esiintymät annetussa merkkijonossa. */ public static void main(string[] args) Scanner lukija = new Scanner(System.in); System.out.println("Anna merkkijono"); String kohde = lukija.nextline(); System.out.println("Anna etsittava merkki "); char c = (lukija.nextline()).charat(0); // rivin ensimmäinen ja ainoa merkki System.out.println("Etsitaan merkin " + c +" esiintymat merkkijonosta " + kohde); 6 Javan kehitystyössä on yleensä voimassa seuraava ominaisuus: uudesta versiosta ei poisteta aiemman version ominaisuuksia. Tällä taataan vanhojen Java-ohjelmien toimivuus uudessa ympäristössä. 13

for (int i=0; i<kohde.length( ); i++) if (kohde.charat(i)==c) System.out.println("Loytyi kohdasta " + i + "."); // if // for // main // class FindPositions2 Lauseke (lukija.nextline()).charat(0) voidaan kirjoittaa myös ilman sulkeita muodossa lukija.nextline().charat(0), koska lauseketta jäsennetään vasemmalta oikealle. Tässä lauseke lukija.nextline() on tyyppiä String ja siihen kohdistetaan luokan String metodi charat. Huomaa, että luokassa Scanner ei ole metodia yhden merkin lukemiseen, joten yhden merkin lukeminen tulee suorittaa tässä esitetyllä tavalla. Edellä tarkasteltava merkki tallennettiin char-tyyppiseen muuttujaan c ja se onkin luonnollista. Voimme tarkastella sitä myös yhden merkin mittaisena String-tyyppisenä merkkijonona (alla muuttuja st). Tällöin meidän tulee tutkia onko ko. merkin muodostava merkkijono st alkuperäisen merkkijonon kohde osajono eli onko kohde.substring(i,i+1) sama kuin st. Merkkijonojen yhtäsuuruutta tulee tutkia luokan String metodilla equals eli meidän tulee kirjoittaa: st.equals(kohde.substring(i,i+1)). Voimme siis kirjoittaa: public static void main(string[] args) Scanner lukija = new Scanner(System.in); System.out.println("Anna merkkijono"); String kohde = lukija.nextline(); System.out.println("Anna etsittava merkki "); String st = lukija.nextline(); System.out.println("Etsitään merkin " + st + " esiintymät merkkijonosta " + kohde); for (int i=0; i<kohde.length( ); i++) if (st.equals(kohde.substring(i,i+1))) System.out.println("Löytyi kohdasta " + i + "."); // for // main (*** esimerkin loppu ***) equals-metodi olioiden yhteydessä Kaikilla luokilla on metodi equals, joka on määritely valmisluokassa Object, joka on kaikkien luokkien (myös itsetehtyjen) yliluokka. Metodi equals on kuitenkin määritelty luokassa Object niin, että se tarkoittaa vain viittauksien yhtäsuuruutta eli ==. Näin ollen se ei ole sellaisenaan käyttökelpoinen, joten joissakin luokissa se on uudelleenmääritelty paremmin. Esim. luokassa String equals tarkoittaa merkkijonojen samuutta kuten nähtiin edellisessä esimerkissä. Monissa muissa luokissa kuten esim. jatkossa esitellyissä muissa merkkijonoluokissa StringBuffer ja StringBuilder kuten myös seuraavalla viikolla käsiteltävien dynaamisten listojen 14

implementoinnissa metodia ei ole uudelleenmääritelty, joten tarvittaessa equals metodi tulee kirjoittaa itse. Luokat StringBuffer ja StringBuilder Luokan StringBuffer oliot ovat merkkijonoja (puhutaan myös merkkijonopuskuriolioista), mutta niiden sisältöä voi muuttaa eli luokassa StringBuffer on metodeja, joilla voimme muuttaa ko. luokan olioita. Luokan String alkiot ovat siis mutatoitumattomia, kun taas luokan StringBuffer oliot ovat mutatoituvia. Esimerkiksi jos halutaan muuttaa tietyssä merkkijonossa tiettyjä merkkejä toisiksi luomatta uutta oliota, niin on järkevää määritellä kyseinen merkkijono luokan StringBuffer olioksi. Luokan olion luonti ja olion viittauksen asetus muuttujaan suoritetaan seuraavasti: StringBuffer <muuttujan nimi> = new StringBuffer(<String-tyyppinen olio>); missä <String-tyyppinen olio> on String-tyyppinen vakio, lauseke tai muuttuja. Tyypit String ja StringBuffer (ja vastaavasti StringBuilder) eivät ole sijoitusyhteensopivia eli String-tyyppiseen muuttujaan ei voi suoraan sijoittaa StringBuffer-tyyppistä alkiota (eikä päinvastoinkaan). Tarvittaessa meidän tulee tehdä tyypin muunnos ja luoda uusi halutun luokan olio, jonka sisältö vastaa alkuperäisen olion sisältöä. Muutos tehdään seuraavasti: String-oliosta vastaava StringBuffer-tyyppinen olio: Olkoon st luokan String olio (tai merkkijonovakio). Tällöin voimme luoda uuden StringBuffer-tyyppisen olion stb kirjoittamalla StringBuffer stb = new StringBuffer(st); Jos tässä jätetään argumentti st pois, niin silloin olion sisältönä on tyhjä merkkijono. StringBuffer-oliosta vastaava String-tyyppinen olio: Olkoon stb luokan StringBuffer olio. Tällöin voimme luoda uuden String-tyyppisen olion st kirjoittamalla String st = new String(stb); Vaihtoehtoisesti voimme kirjoittaa String st = stb.tostring( ); Tässä on myös hyvä huomata, että eksplisiittiset tyypinmuunnokset eivät onnistu kirjastoluokkien tyyppien välillä samaan tapaan kuin perustyypeillä (esim. double vs. int); esim. emme voi kirjoittaa StringBuffer stb = (StringBuffer) st; Lisäksi on hyvä huomata, että luettaessa merkkijono on se aina tyyppiä String ja jos siitä halutaan muodostaa luokan StringBuffer olio, tulee käyttää em. tyypin muunnosta. Lisäksi luokasta String tutut operaatiot + (katenointi) ja olion luonti ilman new:tä ei onnistu luokassa StringBuffer, vaan ne tulee suorittaa oikeaoppisesti käyttäen luokan metodeja. Myöskään merkkijonovakiota ei voi asettaa suoraan StringBuffer-olion arvoksi, koska merkkijonovakio on aina tyyppiä String. 15

Liitteessä 1 on suomennettuna joitakin luokan StringBuffer metodeja ja niiden toiminta. Kattavampi kuvaus löytyy luokkakirjastosta. Esimerkki. Alla on esimerkki merkkijonon kääntämisestä kun metodi käännä saa argumenttinaan sekä palauttaa StringBuffer-tyyppisen olion. Tämä sama metodi esitettiin myös jakson AOP opiskeluoppaassa, mutta tällöin alkiot olivat String-tyyppisiä. Tämän metodin tekeminen on turhaa, koska luokassa StringBuffer on valmiina metodi reverse, joka tekee saman asian. Ohjelmasta näet kuitenkin metodien käännä ja reverse erilaisen soveltamistavan: Metodia käännä ei kohdisteta olioon, koska se on luokkametodi (määreenä on static). Tällöin käännettävä merkkijono (muuttuja kohde) annetaan metodille parametrina. Sen sijaan reverse on luokan StringBuffer esiintymämetodi (luokkakirjastossa metodin reverse kuvauksessa ei ole määrettä static), joten sitä käytetään olio-ohjelmoinnin periaatteiden mukaisesti: metodi kohdistetaan johonkin ko. luokan olioon kirjoittamalla <olio>.<metodin kutsu> eli kuten alla: kohde.reverse( ). Metodissa käännä käytetään metodia append, joka lisää yhden merkin nykyisen olion perään. Tässä meillä on siis käytössä vain yksi olio, joka mutatoituu (muuttuu) ohjelman suorituksen aikana. Metodin append kuvaus kirjastoluokassa StringBuffer on muotoa: StringBuffer append(char c) Appends the string representation of the char argument to this sequence Kun klikkaamme append-sanaa saamme tarkemman kuvauksen: public StringBuffer append(char c) Appends the string representation of the char argument to this sequence. The argument is appended to the contents of this sequence. The length of this sequence increases by 1. The overall effect is exactly as if the argument were converted to a string by the method String.valueOf(char) and the character in that string were then appended to this character sequence. Parameters: Returns: c - a char. a reference to this object. // reference = viittaus Huom. Vaikka append on esiintymämetodi (koska sana static puuttuu metodin otsikkoriviltä), niin se on funktio, jonka soveltaminen palauttaa StringBuffer-olion. Soveltaminen on siis lausekelause, jota voi käyttää lauseena tai lausekkeena. Esimerkiksi alla kutsulla apu.append(st.charat(i)) on myös arvo, joka on sama kuin apu:n muuttunut sisältö. Tätä arvoa ei useinkaan ole tarvetta asettaa minkään toisen muuttujan arvoksi, vaikka se mahdollista onkin. 16

public class Kaanna_buffer public static void main(string[] args) System.out.println( Anna merkkijono ); String st = OmaIO.lueString(); // String-tyyppisestä oliosta st luodaan StringBuffer-tyyppinen olio nimeltä kohde StringBuffer kohde = new StringBuffer(st); System.out.println(käännä(kohde)); System.out.println(kohde.reverse( )); // end main /** Metodi palauttaa merkkijonon st käännettynä. * Alkuehto: st tulee olla luotu, mutta se voi olla tyhjä. */ public static StringBuffer käännä(stringbuffer st) // luodaan ensin uusi olio, jonka sisältönä on tyhjä merkkijono StringBuffer apu=new StringBuffer( ); // lisätään sen loppuun st:n merkit yksitellen lopusta alkaen for (int i=st.length( )-1; i>=0; i--) apu.append(st.charat(i)); // ks. yllä oleva Huom. return apu; // metodi käännä // class Kaanna_buffer Lause apu.append(st.charat(i)); lisää merkkijonon apu perään merkin st.charat(i) eli merkkijonon st positiossa i olevan merkin. (*** esimerkin loppu ***) Java 5.0:sta lähtien mukana on myös luokka StringBuilder, joka on kuin luokka StringBuffer, mutta luokan StringBuilder kuvauksessa suositellaan sen käyttöä StringBufferin sijasta tehokkuuden vuoksi. Katso luokkakirjastosta sen kuvaus. Kuten jo aiemmin todettiin, luokkien StringBuilder ja StringBuffer osalta tulee huomioida myös seuraava: metodi equals antaa arvon true vain silloin kun viitataan samaan olioon (siis toimii samoin kuin ==). 17

Luokka StringTokenizer ja luokan String metodi split Luokkaa StringTokenizer käytetään osien (tokens eli tokenien) erottamiseen ja poimimiseen merkkijonosta, jossa on käytetty tiettyjä erotinmerkkejä. Erotinmerkit voidaan antaa konstruktorille parametrina olion luonnin yhteydessä. Esimerkiksi StringTokenizer stok = new StringTokenizer(<merkkijono josta etsitään>, <erotinmerkit merkkijonona>); Jos erotinmerkkejä ei anneta, niin oletuksena on white-space merkit (välilyönti, tabulaattori, enter). Lisäksi konstruktorille voidaan antaa kolmas parametri (ks. alla olevan esimerkin muuttujan st4 luonti). Esimerkki. Esitämme esimerkkiohjelman, jossa havainnollistetaan luokan metodien toimintaa. Metodissa luodaan läpikäytävä merkkijono-olio st2 käyttäen konstruktoria StringTokenizer(String str, String delim) Constructs a string tokenizer for the specified string. jossa erotinmerkki delim annetaan merkkijonona. Ohjelmassa käytetään myös luokan StringTokenizer esiintymämetodia nexttoken: String nexttoken() Returns the next token from this string tokenizer. Metodin nexttoken kutsu kohdistetaan StrngTokenizer-olioon ja kutsu palauttaa merkkijonon seuraavan osan. 18

Katso rivien perässä olevat kommentit. import java.util.*; public class Tokenit public static void main(string[] args) StringTokenizer st1= new StringTokenizer("a b 1"); System.out.println(st1.countTokens()); // tulostuu 3 String s = st1.nexttoken(); // s="a" s = st1.nexttoken(); // s="b" s = st1.nexttoken(); // s="1" StringTokenizer st2 = new StringTokenizer("xx, yy,11", ","); s = st2.nexttoken(); // s="xx" s = st2.nexttoken(); // s=" yy" int i = Integer.parseInt(st2.nextToken()); // i=11 (tyypin muunnos!) /* jotta yllä oleva lause toimisi, niin merkkijonossa ei saa olla merkkien 11 kummallakaan puolella tyhjiä */ StringTokenizer st3 = new StringTokenizer("23+444-5","+-"); // sekä + että - ovat erottimia s = st3.nexttoken(); // s="23" char ch = st3.nexttoken().charat(0); // ch='4' s = st3.nexttoken(); // s="5" StringTokenizer st4 = new StringTokenizer("23+444-5","+-", true); // true saa aikaan sen, että myös erotinmerkki tulkitaan tokeniksi s = st4.nexttoken(); // s="23" ch = st4.nexttoken().charat(0); // ch='+' s = st4.nexttoken(); // s="444" // main // class Tokenit (*** esimerkin loppu ***) Luokassa String on myös kätevä metodi split, jolla kohdemerkkijono voidaan palastella merkkijonotaulukkoon. Tehokkuussyistä tätä metodia suositellaan käytettävän luokan StringTokenizer metodien sijasta. Lisäksi splitin käyttö on usein helpompaa. Tarkastellaan metodia esimerkin avulla, joten olkoon String st= 123,456,7 ; Metodin split argumenttina on ns. säännöllinen lauseke (regular expression) 7 String-tyyppisenä, joka määrää sen mistä kohdin palastelu tehdään: yksi merkki: esim. lause String[ ] s = st.split(, ); pilkkoo st:n palasiin pilkkujen kohdilta, jolloin s[0]= 123, s[1]= 456, s[2]= 7 useita peräkkäisiä merkkejä: esim. lauseen String[ ] s = st.split( 456 ); jälkeen s[0]= 123, ja s[1]=,7 lista vaihtoehtoisista merkeistä, joiden kohdalta suoritetaan paloittelu. Ne annetaan hakasulkeiden sisällä peräkkäin: esim. lauseen String[ ] s = st.split( [25] ); jälkeen s[0]= 1 ja s[1]= 3,4 ja s[2]= 6,7. yksi tai useampi välilyönti peräkkäin: split( + ) (plussan edessä on yksi välilyönti) 7 Ei vaadita yleisesti tällä kurssilla. Alla olevien esimerkkien tapaukset riittää osata. 19

Seuraavaksi mennään hiukan teknisempään mutta käytännössä hyvinkin tarpeelliseen asiaan: desimaalilukujen muotoilu. Tätä ei kuitenkaan vaadita tentissä. Asiasta esitetään vain esimerkkejä. Tulostuksen muotoilu ja DecimalFormat Usein desimaaliluvuissa on tulostuksen yhteydessä liian paljon desimaaleja; meille riittäisi esimerkiksi vain kaksi desimaalia. Jakson AOP harjoitustehtävissä esiteltiin tulostuslause printf, joilla voidaan muotoilla (formatoida) desimaaliluku haluttuun muotoon. Esimerkiksi olkoon: double d=1.236; System.out.printf("d=%8.2f", d); Tämä saa aikaan tulostuksen d= ja sen jälkeen luku d tulostetaan 8 merkin levyiseen kenttään kahdella desimaalilla. Tässä voi kirjoittaa myös esim. %2.2f, jolloin desimaaliluvun eteen tulee vain yksi välilyönti ja tarkkuus on edelleen 2 desimaalia. Tässä siis tapahtuu automaattinen kentän laajennus, koska 2 on liian pieni luku koko kentän leveydeksi. Lisäksi jos luvussa on enemmän desimaaleja kuin mitä tulostetaan, niin muunnoksessa suoritetaan pyöristys (jos siis ensimmäinen poisjäänyt desimaali on >=5). Joskus on tarvetta muodostaa desimaaliluvusta String-tyypin olio, joka vastaa luvun esitystä mutta vähemmillä desimaaleilla. Tällöin voimme käyttää luokkaa DecimalFormat, joka vaatii import-lauseen import java.text.decimalformat; Tämän luokan käyttö käy ilmi seuraavasta esimerkistä: DecimalFormat f = new DecimalFormat("0.00"); // ja oliohan tämä formatoijakin on! double d=1.236; String st = d= +f.format(d); Tässä f.format(d) palauttaa (johtuen kielivalinnasta kuten Scannerin yhteydessäkin) Stringtyyppisen arvon 1,24, joten jos haluaa desimaalipisteen pilkun tilalle, niin tulee kirjoittaa f.format(d).replace(,,. ) eli korvataan pilkku pisteellä. Tässäkin tapahtuu automaattinen kentän laajennus, jos muotoilussa (edellä "0.00") on liian vähän nollia desimaalipisteen edessä muotoiltavaan lukuun nähden. Merkkijonon ja tekstitiedoston läpikäynti käyttäen luokkaa Scanner Luokkaa Scanner (ks. jakson AOP opiskeluoppaan lopussa oleva Liite) voi käyttää merkkijonon skannaukseen samaan tapaan kuin luokkaa StringTokenizer. Läpikäytäessä merkkijonoa, voi erotinmerkin valita itse. Tarkastellaan esimerkkinä merkkijonossa olevien lukujen läpikäyntiä. Olkoon s merkkijono, joka sisältää double-lukuja, jotka on erotettu #-merkeillä; esim. s= 1,5#2,89#3,13 (huomaa desimaalipilkku!). Nyt luomme luokan Scanner olion, jolle annetaan parametrina se merkkijono, joka käydään läpi. Koska erotinmerkkinä on nyt #, niin meidän tulee kertoa ko. oliolle, että oletuserottimen sijasta erottimena on #. Merkkijonossa ei saa olla kuitenkaan esim. ylimääräisiä välilyöntejä. 20

public static void main (String[ ] args) String s="1,5#2,89#3,13"; int luettuja = 0; double summa = 0; Scanner scan = new Scanner(s); scan.usedelimiter("#"); while (scan.hasnext()) luettuja++; int luku = scan.nextdouble(); summa = summa + luku; // while if (luettuja > 0) System.out.println("Lukujen keskiarvo on " + summa/luettuja); else System.out.println("Ei ole mitään laskettavaa."); // main Jos s:n erotinmerkkeinä olisikin välilyönnit, niin silloin ohjelmasta tulisi poistaa lause scan.usedelimiter("#"); Tällöin s:ssä voisi lukujen välissä olla myös enemmän kuin yksi välilyönti. Jos halutaan erotella merkkijonosta osia merkkijonoina (tyyppiä String), niin silloin tulee kirjoittaa String osajono = scan.next(); Jatketaan edellistä vielä niin, että luvut ovat tekstitiedostossa luvut.txt ja että tiedostossa voi olla useita rivejä, esim. tiedosto voi olla muotoa: 1#2#3 4#5#6 Alla on ohjelma, joka lukee luvut tiedostosta ja laskee niiden keskiarvon. Ohjelma lukee silmukassa tiedostoa rivi kerrallaan merkkijonomuuttujaan rivi. Jakson AOP opiskeluoppaan s. 103 käsiteltiin vastaava esimerkki, mutta tällöin tiedostoa luettiin luku kerrallaan eikä riveittäin ja lukujen erotinmerkkinä oli tavallinen white space -merkki eikä # kuten tässä. Tiedostojen käsittely vaatii aina määreen throws IOException metodin otsikkoriville. Tämä tarkoittaa sitä, että metodi voi nostaa ns. poikkeuksen virheellisen IO-toiminnan yhteydessä. Poikkeuksia tarkastellaan lähemmin myöhemmin. Tässä poikkeusta (virhettä) ei siepata siihen tarkoitetulla lauseella try catch, vaan ohjelman annetaan kaatua. 21

import java.util.scanner; import java.io.*; public class StringiScannerTiedostosta public static void main (String[ ] args) throws IOException Scanner näppäimistöscan = new Scanner(System.in); //luodaan näppäimistöskanneri System.out.println("Anna tiedoston nimi"); String tiedostonnimi = näppäimistöscan.nextline(); // luetaan tiedoston nimi näppäimistöltä Scanner tiedostoscan = new Scanner(new File(tiedostonNimi)); // luodaan tiedostoskanneri int luettuja = 0; double summa = 0; while (tiedostoscan.hasnext()) String rivi=tiedostoscan.nextline(); // muuttujaan rivi asetetaan tiedoston seuraava rivi System.out.println("Luettu rivi on " + rivi); Scanner merkkijonoscan = new Scanner(rivi); // luodaan merkkijonoskanneri merkkijonoscan.usedelimiter("#"); while (merkkijonoscan.hasnext()) luettuja++; int luku = merkkijonoscan.nextint(); summa = summa + luku; // while merkkijonoscan // while tiedostoscan if (luettuja > 0) System.out.println("Lukujen keskiarvo on " + summa/luettuja); else System.out.println("Ei ole mitään laskettavaa."); // main // class Anna tiedoston nimi luvut.txt Luettu rivi on 1#2#3 Luettu rivi on 4#5#6 Lukujen keskiarvo on 3.5 Press any key to continue... Random Luokkaa Random käsiteltiin jo jaksolla AOP, mutta palataan siihen vielä hetkeksi. Kertaa ensin jakson AOP opintomonisteesta luokkaa Random koskeva luku. Voidaksemme generoida satunnaisia lukuja, meidän tulee luoda luokan Random olio (satunnaislukuolio) ja soveltaa siihen luokan esiintymämetodeja nextint, nextlong, nextfloat tai nextdouble, jotka palauttavat (seuraavan) satunnaisen int-, long-, float tai double-tyyppisen satunnaisluvun. Luokan Random olio luodaan joko lausekkeella Random(); tai Random(x); missä x on long-tyyppinen vakio tai muuttuja. Esimerkiksi Random generaattori = new Random(); tai Random generaattori = new Random(x); 22

Jos haluat ohjelman jokaisella suorituskerralla saman satunnaislukujen jonon 8, tulee käyttää jälkimmäistä tapaa kiinteällä x:n arvolla. Luokan Random metodi nextint(n), missä n:n pitää olla positiivinen kokonaisluku, palauttaa satunnaisen kokonaisluvun väliltä 0...n-1. Jos halutaan asettaa muuttujaan k satunnainen kokonaisluku väliltä a b (missä a ja b ovat kokonaislukuja ja a<b), niin silloin kirjoitetaan 9 : Random sat = new Random(); Esimerkiksi väliltä 1 39: int k = sat.nextint(39)+1; int k = sat.nextint(b-a+1)+a; Liite 1 s. 93 ohjelma RollDice. Ohjelman tarkoituksena on simuloida nopan heittoa (voimme siis heittää noppaa ilman noppaa). Jokaisen heiton tuloksena on kokonaisluku väliltä 1 6. Ohjelmalla on kaksi käyttötapaa: jos sille annetaan argumenttina yksi kokonaisluku, ohjelma tulostaa kyseisen määrän nopanheiton tuloksia; annettaessa ohjelmalle argumenttina 2 kokonaislukua, tarkoittaa jälkimmäinen generaattorin siemenlukua, jonka perusteella se laskee ensimmäisen satunaisluvun arvon. Esimerkiksi käskyllä Rolldice 100 ohjelma tulostaa 100:n nopanheiton tuloksen. Nämä kaksi tapausta voidaan tutkia ehtolausekkeella args.length==2. Ohjelmassa esitellään satunnaislukugeneraattoriolio noppa, jolloin lausekkeella noppa.nextint() saadaan selville seuraava satunnainen kokonaisluku. Kun se muutetaan ensin positiiviseksi (abs), jaetaan se 6:lla, niin jakolaskun jakojäännös on satunnainen kokonaisluku väliltä 0 5. Kun tähän lisätään 1, saadaan haluttu arvo. Kaikki tämä lasketaan lausekkeella Math.abs(noppa.nextInt()) % 6 + 1. Ohjelma tulostaa 35 tulosta peräkkäin niin, että kahden luvun välissä on aina välilyönti. Sen jälkeen suoritetaan rivinvaihto. Tämä saadaan aikaan ottamalla käyttöön laskuri ja kun se saa arvon 35, tulostetaan rivinvaihto. Luokakirjastojen toteutukset Kirjastoluokkien toteutukset (koodit) löytyvät koneeltasi jdk-hakemistosta ja ne ovat tiedostossa src.zip ja löytyvät myös esim. osoitteesta http://sourceforge.net/projects/jdk7src/ Niitä on hyödyllistä tutkia, joskin niiden sisältö ei kuulu kurssivaatimuksiin. Tässä on hyvä huomata, että esim. luokan String pohjalla oleva tallennusrakenne on merkkitaulukko char[] (ks. jaksolta TTP I ohjelmointikielten tallennusrakenteet). Samoin ensi viikolla käsiteltävä dynaaminen lista Vector toteutetaan staattisen taulukon avulla, vaikka luokan Vector käyttäjä ei sitä mistään huomaakkaan. 8 Tämä saattaa olla tarpeellista esim. testausvaiheessa. 9 Tämä oli jakson AOP viimeisen viikon harjoitustehtävä 23

Harjoitustehtävät Tutustu kirjastoluokkiin Math, StringBuffer, StringBuilder, StringTokenizer ja Random. Katso koneesi Java-kansion (hakemiston) alta kansioista \docs\api\java\lang ja \docs\api\java\util. Kaksoisklikkaa vastaavaa html-tiedostoa. Tutki konstruktoreita ja metodeja ja huomaat, että sieltä löytyy paljon enemmän metodeja kuin Liitteen 1 taulukoista. http://docs.oracle.com/javase/8/docs/api/ Kaikkien viikkojen tehtävien yhteydessä tulee esittää aina metodien ulkoinen kuvaus ja mahdollinen alkuehto. Kirjoita myös pääohjelma (main-metodi), jolla voit testata metodiasi. Jos lähetät ratkaisusi, liitä mukaan kuvaruutukaappaus, joka todentaa sen, että metodisi/ohjelmasi toimii. 1. Kirjoita metodi, joka palauttaa tiedon siitä kuinka monta kertaa parametrina annettu merkki (tyyppiä char) esiintyy parametrina annetussa merkkijonossa (tyyppiä StringBuilder). Lisäkysymys: Jos muuttuja st on tyyppiä String, niin miten saat siitä StringBuilder-tyyppisen muuttujan stb? Entä päinvastoin eli StringBuilder -> String? Ovatko luokkien StringBuilder ja StringBuffer alkiot sijoitusyhteensopivia? 2. 3 10. Pieni käyttäjän yhteenlaskutaitoa testaava ohjelma: Kirjoita ohjelma, joka 1) generoi kaksi satunnaista kokonaislukua väliltä 1 100, 2) tulostaa ne ruudulle ja kysyy mikä on näiden summa, 3) lukee käyttäjän näpyttelemän vastauksen ja 4) antaa palautteen tuloksen oikeellisuudesta. Rakenna tämän ympärille toistorakenne, jossa kysytään jokaisen laskutoimituksen jälkeen vastaus kysymykseen Haluatko jatkaa?. Lopuksi ohjelma tulostaa kuinka monta prosenttia tuloksista oli oikein. Tee ohjelmasta kaksi versiota: toinen käyttää lukemiseen luokkaa OmaIO ja toinen luokkaa Scanner. Ohje: Tässä tarvitaan luokkaa Random. Tässä riittää pelkkä main eli sinun ei tarvitse välttämättä modularisoida ohjelmaa tekemällä muita metodeja. Luokan Scanner metodeista kannattaa valita nyt sekä merkin että luvun lukemiseen metodi nextline(). Miksi? Testaa ohjelmasi tietokoneella. Jos lähetät ratkaisun, mukana tulee olla myös kuvaruutunäyttö ohjelman suorituksesta. 4. -5. Kirjoita metodi, jolle annetaan parametrina merkkijono (String), jossa on kahden positiivisen (etumerkittömän) kokonaisluvun yhteen tai vähennyslasku ja joka palauttaa lausekkeen arvon int-tyyppisenä. Tässä siis voi olla joko yhteenlasku tai vähennyslasku ja tämä tulee ottaa huomioon metodissa. Esim. Parametri: 21+53, tulos: 74. Tee tästä kaksi eri ratkaisua: Toinen käyttää luokkaa StringTokenizer (Tehtävä 4) ja toinen luokan String metodia split (Tehtävä 5). Testaa ohjelmasi tietokoneella. Jos lähetät ratkaisun, mukana tulee olla myös kuvaruutunäytöt ohjelmien suorituksesta. 10 Kahden tehtävän arvoisista tehtävistä voit merkitä toisen (esim. tehtävän 2), jos olet mielestäsi tehnyt n. puolet koko tehtävästä. Menettele vastaavasti kolmen tehtävän arvoisten tehtävien kohdalla. 24