Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Poikkeukset ja tietovirrat: Virhetilanteiden ja syötevirtojen käsittely
Poikkeukset Poikkeuksella tarkoitetaan yllättävää ajonaikaista tilannetta, joka estää ohjelman normaalin suorituksen. Esimerkkejä: nollalla jako avattavaa tiedostoa ei löydy saadaan syötteenä tekstiä, vaikka yritetään lukea kokonaisluku viitataan taulukon alkioon, jonka indeksi on indeksirajojen ulkopuolella. Vesa Ollikainen & Outi Grotenfelt 2
Poikkeusten ryhmät Javassa poikkeus on olio, joka luodaan ongelmatilanteen syntyessä. Poikkeusten ryhmät 1. tarkistettavat poikkeukset syntyvät tilanteissa, joihin hyvin kirjoitetun ohjelman on varauduttava (esim. virheellinen tiedostonimi) ohjelmoijan on määritettävä poikkeuksen käsittely (tarkistetaan käännösvaiheessa) 2. virheet järjestelmän väärä toiminta (esim. viallinen laite) poikkeukseen ei tarvitse/ei voi varautua 3. ajonaikaiset poikkeukset seurausta ohjelmointivirheistä pyritään välttämään, ei tarvitse varautua Virheitä ja ajonaikaisia poikkeuksia kutsutaan tarkistamattomiksi poikkeuksiksi. Vesa Ollikainen & Outi Grotenfelt 3
Esimerkki: nollalla jako Tarkastellaan esimerkkinä ohjelmaa, joka selvittää, montako makeista jokaiselle riittää, kun makeispussin sisältö jaetaan tasan. Esimerkeissä käytetään esimerkkinä poikkeuksesta ajonaikaista virhettä: nollalla jakoa. Nollalla jakoa käytetään esimerkissä yksinkertaisuuden vuoksi. Kyseiseen virhetilanteeseen olisi luontevampaa varautua perinteisin keinoin. Toistorakenne syötteen kysymiseksi uudelleen, jos jakajana on nolla. Vesa Ollikainen & Outi Grotenfelt 4
Esimerkki: nollalla jako import java.util.*; public class Jakaja { public static Scanner input = new Scanner(System.in); public static void main(string[] args) { int lkm, henkilot, annos; System.out.print("Montako makeista pussissa on: "); lkm = input.nextint(); System.out.print("Monelleko henkilölle ne jaetaan: "); henkilot = input.nextint(); annos = lkm / henkilot; System.out.println("Jokainen saa "+annos+" makeista."); Esimerkissä makeisten määrä jaetaan ihmisten määrällä (kokonaisjako). Käyttäjä voi syöttää ihmisten määräksi nollan. Nolla aiheuttaa ArithmeticException-poikkeuksen. run: Montako makeista pussissa on: 10 Monelleko henkilölle ne jaetaan: 0 Exception in thread "main" java.lang.arithmeticexception: / by zero at ekaesim.jakaja.main(jakaja.java:13) Java Result: 1 BUILD SUCCESSFUL (total time: 1 second) Vesa Ollikainen & Outi Grotenfelt 5
Poikkeukseen varautuminen import java.util.*; public class Jakaja { public static Scanner input = new Scanner(System.in); public static void main(string[] args) { int lkm, henkilot, annos; Riskialtis koodi kirjoitetaan try-lohkoon. Jos try-lohkon suoritus aiheuttaa poikkeuksen, hypätään catch-lohkoon, jossa poikkeus run: käsitellään. System.out.print("Montako makeista pussissa on: "); lkm = input.nextint(); System.out.print("Monelleko henkilölle ne jaetaan: "); henkilot = input.nextint(); try { annos = lkm / henkilot; System.out.println("Jokainen saa "+annos+" makeista."); catch (ArithmeticException e) { System.out.println( Virhe: nollajako! ); Montako makeista pussissa on: 10 Monelleko henkilölle ne jaetaan: 0 Virhe: nollajako! BUILD SUCCESSFUL (total time: 1 second) Vesa Ollikainen & Outi Grotenfelt 6
try/catch-rakenne try { // riskialtis koodi catch (poikkeustyyppi_1 e) { // poikkeustyypin 1 käsittely catch (poikkeustyyppi_2 e) { // poikkeustyypin 2 käsittely catch (Exception e) { // kaikkien (muiden) poikkeustyyppien käsittely finally { // lopetustoimenpiteet Vesa Ollikainen & Outi Grotenfelt 7
try/catch-rakenne Poikkeuksenkäsittelijöitä (catch-lohkoja) voi olla useita Suoritettava käsittelijä määräytyy poikkeuksen tyypin mukaan Jos poikkeustyypiksi määritellään Exception, suoritetaan se kaikille poikkeuksille. Jos mukana on poikkeuskohtaisia käsittelijöitä, on yleinen käsittelijä kirjoitettava viimeiseen catch-lohkoon. Finally-lohkon toimenpiteet suoritetaan joka tapauksessa try-lohkon suorituksen jälkeen tai poikkeuksenkäsittelijän suorituksen jälkeen. Vesa Ollikainen & Outi Grotenfelt 8
Poikkeuksen siirto import java.util.*; public class Jakaja2 { public static void jaakarkit() throws ArithmeticException{ int lkm, henkilot, annos; Scanner input = new Scanner(System.in); System.out.print("Montako makeista pussissa on: "); lkm = input.nextint(); System.out.print("Monelleko henkilölle ne jaetaan: "); henkilot = input.nextint(); annos = lkm / henkilot; System.out.println("Jokainen saa "+annos+" makeista."); Poikkeus voidaan siirtää kutsuvan ohjelmanosan tai virtuaalikoneen käsiteltäväksi. throws-lauseella luetellaan siirrettävät poikkeukset. Vesa Ollikainen & Outi Grotenfelt 9
Poikkeuksen käsittely kutsuvassa luokassa Siirretty poikkeus on käsiteltävä kutsuvassa lohkossa tai siirrettävä eteenpäin virtuaalikoneelle. Vesa Ollikainen & Outi Grotenfelt 10
Oman poikkeusluokan luonti Oma poikkeusluokka määritetään Exception-luokan aliluokaksi. Jos poikkeusluokasta tehtäisiin RunTimeException-luokan aliluokka, ei käännösaikana vaadittaisi poikkeuksen sieppaamista. Varattu ohjelmointivirheille (APIn väärän käytön varalta) Poikkeuksen käsittelytoimenpiteet on kirjoitettu poikkeusluokan konstruktoriin. Tässä vasta luodaan poikkeusoliota, mutta ei tulosteta mitään. Poikkeusluokan konstruktori kutsuu yliluokan (Exception) konstruktoria, joka saa parametrinaan virheilmoituksen. Vesa Ollikainen & Outi Grotenfelt 11
Oman poikkeusluokan käyttö Poikkeus luodaan throw-lauseella. Tarvittava poikkeusolio voidaan luoda samalla (new). Vesa Ollikainen & Outi Grotenfelt 12
Oman poikkeusluokan käyttö Testiluokassa on käsiteltävä heitetty poikkeus tai siirrettävä se edelleen virtuaalikoneelle. Tässä kutsutaan poikkeusoliolle Exception-luokasta perittyä metodia printstacktrace. Metodi kutsuu poikkeusolion tostring-metodia (jolla on nyt tieto poikkeukseen liitettävästä merkkijonosta). Tämän jälkeen printstacktrace-metodi kutsuu metodia, joka tulostaa odottavien metodien pinon Vesa Ollikainen & Outi Grotenfelt 13
Tietovirrat Poikkeusten käsittely (erityisesti IOException) on keskeistä tietovirtojen käytössä. Tietovirta on yksisuurtainen syöte- tai tulostevirta syötevirrasta luetaan tulostevirtaan tulostetaan Pakkaus java.io sisältää valmiita luokkia tietovirtojen käsittelyyn. Tietovirran käsittelyn vaiheet tietovirta luodaan (jolloin tiedosto avataan) tietoa luetaan yleensä toistorakenteen sisällä tiedosto suljetaan Virhetilanteiden synnyttämiin poikkeuksiin (esim. tiedosto puuttuu tai on tyhjä) on varauduttava. Vesa Ollikainen & Outi Grotenfelt 14
Merkkipohjaiset tietovirrat FileReader-luokan avulla voidaan avata tiedosto. BufferedReader-oliosta voidaan lukea syötettä rivi kerrallaan. FileReader-olio annetaan parametrina. Rivin jäsentäminen voidaan tehdä String.split-metodin avulla Seuraava esimerkki lukee henkilöiden UTF-8-koodattua verenpainedataa ja tulostaa sen konsolille muotoiltuna. Esimerkkitiedostoa: Vesa Ollikainen & Outi Grotenfelt 15
Esimerkki Vesa Ollikainen & Outi Grotenfetl 16
Tietovirtojen käsittelystä Syötteen kirjoittamiseen on analogiset luokat FileWriter BufferedWriter Syötteitä ja tulosteita voidaan käsitellä myös tavupohjaisesti. FileInputStream / FileOutputStream tiedostoje käsittelemiseksi DataInputStream / DataOutputStream -luokat perustietotyyppien syöttämiseksi ja tulostamiseksi Vesa Ollikainen & Outi Grotenfelt 17
Oliovirrat Oliovirtojen avulla voidaan lukea ja kirjoittaa ohjelmassa olevien olioiden tila pysyvää tallennusta varten. Tallennettavien olioiden on toteutettava Serializable-rajapinta. Lukeminen ja kirjoittaminen tapahtuu ObjectInputStream / ObjectOutputStream -luokkien avulla. Vesa Ollikainen & Outi Grotenfelt 18
Esimerkki: Luokka, jonka olioita tallennetaan Vesa Ollikainen & Outi Grotenfelt 19
Esimerkki: Tallennus ObjectOutputStream-luokan metodi writeobject kirjoittaa olion tilan. Vesa Ollikainen & Outi Grotenfelt 20
Esimerkki: Luku ObjectInputStream-luokan metodi readobject lukee olion tilan. Vesa Ollikainen & Outi Grotenfelt 21
THANK YOU! www.metropolia.fi/en/ www.facebook.com/metropoliaamk outi.grotenfelt@metropolia.fi