- Ohj2, luennot 17-18, 15.4.-16.4.2005
- Tiedostot ja tietovirrat
- Materiaali
- Moniste, luku 17
- TIJ, luku 11
- ks. Sunin IO tutorial
- [ http://java.sun.com/docs/books/tutorial/essential/io/index.html ]
- Merkkijonopohjainen tiedostonkäsittely
- Erota-funktio revisited...
- Yleismalli: lue tiedostoa rivi kerrallaan ja käsittele rivillä olevat tiedot
- Tiedostonkäsittely Kerhoon: lisää Jäsen- ja Harrastusluokkiin toString- ja parse-metodit ja tietorakenneluokkiin tiedoston luku ja luettujen olioiden lisääminen rakenteeseen
- Tietovirrat ja lukijat
- luokkahierarkia, ks. reading from is.
- Java 1.0-ratkaisu: Stream-luokat - byte-tason käsittelyä (8 bit)
- Java 1.1-ratkaisu: Reader-luokat - merkkitason käsittelyä (16 bit)
- Korvaa osittain Stream-luokat
- System.In ja System.out ovat (historiallisista syistä?) Streameja
- Streameja kannattaa edelleen käyttää binääritiedostoihin (esim zip stream)
- Streamin voi muuttaa Readeriksi adapterioliolla (esim. InputStreamReader)
- Java 1.4 lisää tähän nio (New IO) -luokat
- Tarkoituksena parantaa IO-luokkien suorituskykyä
- Sivuutetaan tällä kurssilla
- Huom. luettavan/kirjoitettavan merkkitiedon merkistön voi valita InputStreamReader- ja OutputStreamWriter-luokissa
- Oletuksena käytetään käyttöjärjestelmän omia oletuksia, esim windowsilla 8-bittistä windows-1252-merkistöä (muutamia merkkejä lukuunottamatta identtinen ISO Latin 1-merkistön kanssa)
- Javan sisäinen merkistö on Unicode 16-bittisellä UTF 16-koodauksella
- Tietovirtojen avulla tiedostoja (ja lähes mitä tahansa muutakin tietoa) voidaan käsitellä ns. "piiput ja filtterit"-arkkitehtuurin mukaisesti
- Esim. virtoja voidaan yhdistää (vrt. unix-putket)
- PipedInput/OutputStream-luokkien avulla tietoa voidaan lähettää "putken" avulla säikeestä toiseen
- Luokkia on runsaasti, mutta niillä kaikilla on sama yleisrajapinta: tiedostoja, päätesyöttöä ja muita tietolähteitä voidaan ideaalitapauksessa käsitellä samalla koodilla
- Esimerkit
- Moniste: tiedostoesimerkit
- Tied_ka (vrt. luku näppäimistöltä)
- Sanalaskuri
- Huom. SanatMapGen-tiedostoa ja muita Java5-ohjelmia voi yrittää ajaa JBuilderillakin, kunhan vaihdetaan asetuksista käytettävä JDK (syntax highlightingiin saattaa tosin tulla häiriöitä..)
- Virtaesimerkki (samalla kertaus perinnästä ja komentorivikomennoista, kun lähdekoodi ja luokat eri tiedostoissa - nb4 ja jbuilder-projektit myös valmiina)
- Serialisointi (sarjallistaminen)
- Olion lataus/tallennus levylle javan omalla formaatilla
- rajapinta: serializable
- Ei tarvitse välttämättä tehdä luokalle mitään. Tällöin oletusserialisointi lataa/tallentaa kaikki, paitsi transient-kentät
- voi myös kirjoittaa omat lataus/tallennustoiminnot
- ongelma: jos luokan määritystä muutetaan,serialisointi ei välttämättä toimi
- luokkaan voidaan merkitä "versionumero", jolloin samaa versiota edustavat luokat ovat (samojen attribuuttien osalta) yhteensopivia, vaikka toteutus olisi muuttunut
- Esimerkki: asunnon serialisointi
- Virheiden käsittelystä
- Ks. TIJ, luku 11
- Poikkeukset
- Luokkia, jotka peritään Throwable-luokasta
- Error-luokista (ajonaikainen virhe) ei tarvitse ilmoittaa metodin parametrilistassa, eli niitä periaatteessa tapahtua milloin vain
- Exception-luokat ovat varsinaisia poikkeuksia, joiden käsittely voidaan tarkastaa käännösaikaisesti ja joista täytyy ilmoittaa metodin esittelyrivillä (tai käsitellä metodin sisällä)
- Poikkeus: RuntimeException - käyttäytyy kuten Error-luokka
- poikkeukset ovat olioita - heitetyn poikkeuksen mukana voidaan lähettää ylemmälle tasolle tietoa virhetilanteesta
- pyrkivät korvaamaan C-tyylisen virhetilanteen käsittelyn funktion paluuarvon testauksena
- peruskäyttö: resurssin varaus try-blokin sisälle, finallylla varmistetaan, että tulee aina vapautettua
- Esim. tiedosto suljettava aina käytön jälkeen!
- poikkeuksia ei välttämättä kannata siepata heti havaitessa, vaan sillä tasolla, jolla on riittävästi tietoa virhetilanteen käsittelyyn
- toisaalta kaikkia poikkeuksia ei missään tapauksessa pidä "valuttaa" pääohjelmaan...
- käytännön ongelma: mikä on "oikea" virheenkäsittelytaso?
- poikkeus voidaan ajatella myös kontrolloituna goto-lauseena...
- Huom. poikkeukset konstruktorissa (ks. TIJ)
- Jos poikkeusta ei siepata ollenkaan, virtuaalikone sieppaa sen pääohjelmasta poistuttaessa
- Loogiset tarkastukset l. väittämät (assert)
- käytetään kehitysaikana varmistamaan, ettei ohjelmaan ole päässyt loogisia virheitä
- kääntäjän optioilla assertit voidaan jättää kääntämättä, joten julkaistavan ohjelman suorituskyky ei kärsi väittämistä
- näitä pitäisi olla ohjelmissa huomattavasti nykyistä enemmän!
- ensimmäinen askel kohti ohjelmien formaalia määritystä
- funktion alussa väittämillä voidaan tarkistaa esiehdot, joiden on oltava voimassa funktioon tultaessa
- esim. tyhjälle pinolle ei voida tehdä POP-operaatiota
- funktion lopussa voidaan tarkistaa jälkiehdot, joiden on oltava voimassa funktion jälkeen ('mitä funktio lupaa toteuttaa')
- esim. POP-operaation jälkeen pinon alkioiden lukumäärä vähenee yhdellä
- lisää formaalit menetelmät -kurssilla...
- eivät korvaa poikkeuskäsittelyä, vaan ovat testauksen apuväline
- esim. tiedoston olemassaolon tarkistusta ei voi laittaa väittämäksi, koska tiedosto on sovelluksesta riippumaton resurssi
- Lokitiedostot ja System.err
- System.err on virheilmoituksia varten varattu tietovirta (vrt. System.out), joka tulostuu oletuksena näyttöön
- Esim. poikkeusluokkien virheilmoitukset tulostetaan err-virtaan
- Laajemmissa sovelluksissa err-virta on syytä ohjata tiedostoon tai käyttää erillistä lokitusmekanismia
- Virheiden lisäksi voidaan (ja kannattaa) tulostaa myös muita statistiikkoja ja tilannetietoja
- Esim. tietokantasovelluksessa SQL-lauseet ja niiden suoritusnopeudet
- Useita lokituskirjastoja saatavalla, mm. Javan standardi, apachen logging ja log4j
- Testauksesta
- motivaatio: your code sucks!
- Ks. test infected ja junit cookbook -artikkelit
- [ http://junit.sourceforge.net/ ]
- JUnit: työkalu yksikkötestaukseen (tai: ohjelmoijatestaukseen)
- Idea: jokaista luokkaa varten kirjoitetaan TestCase-luokasta peritty testiluokka, joka sisältää edelleen testimetodeja, joilla voidaan testata kohdeluokan metodien toimivuus
- Projektia varten kirjoitetut testitapaukset voidaan ajaa kerralla, jolloin virheistä voidaan raportoida automaattisesti
- Tavoite: ei enää "debug-merkkijonoja" sekalaisiin paikkoihin tuotantokoodia
- Käytännön haasteita: miten kirjoittaa helposti testattavissa olevaa koodia, miten keksiä hyviä testitapauksia
- Esim. käyttöliittymää, tiedostoja tai tietokantaa käsittelevän koodin testaus
- Eräs lähestymistapa: abstrahoidaan I/O pois testikoodista käyttämällä ns. mock objecteja, jotka käyttäytyvät kuin oikea resurssi, mutta sisältävät vakioidun testidatan
- Pääteohjauksissa harjoittelua
- Lisätietoa kurssilla ohjelmiston testaus ja laadunvarmistus