815338A Ohjelmointikielten periaatteet 2015-2016 VIII Poikkeusten ja tapahtumien käsittely
Sisältö 1. Poikkeusten käsittelyn käsitteitä ja suunnittelukriteerejä 2. Poikkeusten käsittely C++:ssa 3. Poikkeusten käsittely Javassa 4. Tapahtumien käsittely 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 2
VIII.1 Poikkeusten käsittelyn käsitteitä ja suunnittelukriteerejä Varhaisissa ohjelmointikielissä ajon aikainen virhe -> ohjelman kaatuminen Yleensä käyttäjälle käyttöjärjestelmän generoima virheilmoitus Mahdollisesti syöttö- ja tulostustoimenpiteille ajon aikaisten virhetilanteiden käsittely Varsinainen poikkeustenkäsittelymekanismi ensimmäiseksi PL/I kielessä (1960-luvulla) Poikkeusten käsittely yleistynyt vasta 1980-luvulla Nykykielissä tavallisesti jonkinlainen yleinen poikkeustilanteiden käsittelymekanismi 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 3
VIII.1.2 Käsitteitä Poikkeus (exception) Joko laitteistotasolla tai ohjelmatasolla havaittava epänormaali tapahtuma Ei välttämättä virheellinen toiminto, ainoastaan jokin epätavallinen tapahtuma Poikkeusten käsittely (exception handling) Toimenpiteet, jotka poikkeusten havaitseminen aiheuttaa Paikantaminen (detection) Toipuminen (recovering) 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 4
VIII.1.2 Käsitteitä (2) Poikkeusten käsittelijä (exception handler) Käsittelyn suorittaja koodissa Yleensä oma syntaktinen yksikkö Poikkeuksen virittyminen (raise) Poikkeustilanteen aiheutuminen ohjelmassa Poikkeuksen eteneminen (exception propagation) Ohjelman normaalista suorituspolusta erillinen suorituspolku Mahdollistaa poikkeuksen käsittelyn omassa käsittelyyksikössä 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 5
VIII.1.3 Suunnittelukysymyksiä 1. Miten poikkeustenkäsittelijät määritellään ja miten niiden viiteympäristö määräytyy? Käsittelijät koodilohkoja Käsittely voidaan tehdä tapahtumapaikalla Käsittelijät itsenäisiä yksikköjä. Poikkeus pitää lähettää eteenpäin käsiteltäväksi 2. Miten tapahtunut poikkeus sidotaan poikkeuksen käsittelijään? Voidaan tarvita mekanismi valita käsittelijä Poikkeuksen eteneminen ellei sopivaa käsittelijää 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 6
VIII.1.3 Suunnittelukysymyksiä (2) 3. Miten ohjelman suoritus jatkuu poikkeuksen käsittelyn jälkeen? a) Ohjelma voidaan päättää poikkeustilanteessa b) Jatketaan joko poikkeustilanteen aiheuttaman lauseen jälkeisestä lauseesta tai toisesta ohjelmayksiköstä 4. Voiko käyttäjä määritellä omia poikkeuksia? Muoto päätettävä 5. Onko kielessä poikkeuksia valmiiksi? Voiko käyttäjä virittää kielen omia poikkeuksia? 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 7
VIII.1.3 Suunnittelukysymyksiä (3) 6. Miten laitteistotason virhetilanteita käsitellään? Voidaan rajata kokonaan poikkeusten käsittelyn ulkopuolelle ja pitää poikkeuksina ainoastaan ohjelmatason epänormaaleja tilanteita 7. Voidaanko poikkeusten tarkistamista rajoittaa, joko kokonaan tai väliaikaisesti? Esimerkiksi taulukon rajojen tarkistamisesta luopuminen voi tehostaa koodia 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 8
VIII.2 Poikkeusten käsittely C++:ssa Poikkeuksen käsittelijä määritellään 'try-catch' rakenteen catch lohkossa: try { } <Code expected to raise an exception > catch (exception_type_descpriction) { }... < exception handler body > catch (exception_type_descpriction) { } < exception handler body > 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 9
VIII.2 Poikkeusten käsittely C++:ssa (2) Kussakin lohkossa voidaan käsitellä parametrilla määritelty poikkeus Poikkeusta verrataan järjestyksessä lohkojen parametrityyppeihin ja ensimmäinen sopiva suoritetaan Mikäli catch lauseen parametrina käytetään kolmea pistettä (...) [ellipsis], se käsittelee minkä tahansa poikkeuksen Huom! Kirjoita viimeiseksi lohkoksi catch lohkossa mitä tahansa laillista koodia 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 10
VIII.2.1 Poikkeuksen virittyminen C++:ssa Ainoastaan eksplisiittisesti lauseella throw [lauseke] Sanotaan, että poikkeus heitetään *x++=*y++ Pelkkä throw voi esiintyä ainoastaan käsittelijässä -> heittää saamansa poikkeuksen edelleen Voidaan heittää minkä tahansa tyypin tietoa 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 11
VIII.2.2 Poikkeuksen liittäminen käsittelijään C++:ssa Olkoon heitetty poikkeus tyyppiä E ja catch lohkon parametri tyyppiä X. Silloin lohko käsittelee poikkeuksen jos 1. X on samaa tyyppiä kuin E, tai 2. X on luokan E yksikäsitteinen julkinen kantaluokka, tai 3. X ja E ovat osoitintyyppejä, joiden tarkoitetyypeille pätee ominaisuus 1 tai ominaisuus 2, tai 4. X ja E ovat referenssityyppejä, joiden tarkoitetyypeille pätee ominaisuus 1 tai ominaisuus 2 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 12
VIII.2.3 Poikkeuksen eteneminen C++:ssa *x++=*y++ Poikkeus virittyy try lohkossa -> suoritus keskeytyy välittömästi ja poikkeukselle etsitään sopivaa käsittelijää järjestyksessä try lohkoon liittyvistä catch lohkoista Ellei paikallisesti löydy sopivaa käsittelijää, poikkeus etenee kutsuvalle yksikölle jne. kunnes sopiva käsittelijä löytyy tai ohjelma kaatuu 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 13
VIII.2.4 Muita ominaisuuksia Funktio voi määritellä poikkeustyypit, jotka funktio voi heittää antamalla lista poikkeustyypeistä otsikossa class A{}; void heitto(int argh) throw(a,int){ } A mya; int x = 100; if (argh < 0) else throw mya; throw x; Funktio heittää poikkeuksen joka ei esiinny sen poikkeuslistassa -> ajonaikainen virhe Ellei throw määrittelyä, voi heittää mitä tahansa 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 14
VIII.2.4 Muita ominaisuuksia (2) Muistin hallinta Kaikki try lohkon paikalliset pinodynaamiset muuttujat tuhotaan poikkeuksen sattuessa Kekodynaamisia muuttujia ei tuhota -> käsittelijä vastuussa lohkossa varatusta dynaamisesta muistista Poikkeuksia ei voi rajoittaa Ei varsinaisia standardipoikkeuksia Standardikirjastossa määritellään poikkeusluokkia 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 15
VIII.3. Poikkeusten käsittely Javassa VIII.3.1 Javan poikkeukset *x++=*y++ Aina olioita Jakautuvat virheisiin (Error) ja poikkeuksiin (Exception) Kumpikin periytyy luokasta Throwable Jaetaan tarkistettaviin (checked) ja eitarkistettaviin (unchecked) Tarkistettavat poikkeukset on aina käsiteltävä tai heitettävä eteenpäin koodissa Error- ja RuntimeException-luokan poikkeukset eitarkistettavia. Kaikki muut poikkeukset tarkistettavia 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 16
VIII.3.2. Käyttäjän omat poikkeukset Javassa Voidaan kirjoittaa tekemällä oma luokka, joka perii Exception luokan: *x++=*y++ class MyException extends Exception { public MyException( ){ } public MyException(String msg){ super (msg); } } 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 17
VIII.3.3 Poikkeuksien käsittelijä Javassa Määritellään try catch finally -rakenteen catch lohkossa. Syntaksi: try { } lauseet catch(poikkeusluokka1 var1) { } poikkeuslauseet1 [catch(poikkeusluokka2 var2) { poikkeuslauseet2 } catch... finally { lopetuslauseet }] 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 18
VIII.3.4 Poikkeuksen sitominen käsittelijään Javassa Sattunutta poikkeusta verrataan järjestyksessä catch lohkojen parametreihin. Jos poikkeusluokkan tyyppinen poikkeus sattuu, suoritetaan siitä lähtien poikkeuslauseetn ja kontrolli siirtyy catch lauseiden jälkeiseen koodiin. finally -osa suoritetaan joka tapauksessa; myös jos poikkeusta ei satu! Poikkeuksen käsittelijä voi myös heittää uuden poikkeuksen, jonka ei tarvitse olla samaa tyyppiä kuin saatu poikkeus 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 19
VIII.3.5 Poikkeuksen eteneminen Javassa *x++=*y++ Ellei sopivaa catch lausetta, ohjelman kontrolli siirtyy välittömästi poikkeuksen aiheuttanutta metodia kutsuvalle metodille -> tarkastetaan onko sopivaa catch lausetta jne. kunnes poikkeus käsitellään tai kontrolli siirtyy main metodin ulkopuolelle -> ohjelma kaatuu ja konsolille tulostuu virheilmoitus, joka kertoo mikä poikkeus sattui ja missä, esim. Exception in thread "main" java.lang.arithmeticexception: / by zero at NollaJako.main(NollaJako.java:6) 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 20
VIII.3.6 Muita ominaisuuksia Käsiteltävän poikkeuksen tiedot Tapahtumapaikka saadaan kutsupinosta (call stack trace) - voidaan aina kysyä poikkeusoliolta kutsumalla sen metodia printstacktrace() Poikkeusolion metodilla getmessage() saa näkyviin poikkeuksen virheilmoituksen 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 21
VIII.3.6 Muita ominaisuuksia (2) Javan throws lause Määrittelee, mitkä poikkeukset metodi voi heittää Poikkeaa semantiikaltaan C++:n throw lauseesta Esim. int some_method( ) throws MyException, IOException { <function body> } ei voi heittää muita tarkistettavia poikkeuksia kuin MyException ja IOException 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 22
VIII.3.6 Muita ominaisuuksia (3) Poikkeukset luokkien muodostimissa (pätee myös C++:ssa) Muodostimella ei paluuarvoa -> siitä ei voi havaita virhettä Kannattaa käyttää poikkeusta, jos virheellinen alustus mahdollinen Oliota ei luoda, jos muodostimessa poikkeus 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 23
VIII.3.6 Muita ominaisuuksia (4) Huomattava määrä määriteltyjä poikkeuksia Esimerkiksi: Taulukon rajojen ylittäminen -> ArrayIndexOutOfBoundsException, Nollalla jakaminen -> ArithmeticException ja Olioon viittaaminen ennen sen luomista -> NullPointerException Javassa ei ole oletuskäsittelijöitä poikkeuksille Poikkeuksien syntymistä ei voida rajoittaa 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 24
VIII.4 Tapahtumien käsittely Tapahtumia (events) virittyy ulkoisten tapahtumien seurauksena Ilmoitus, että jotain erityistä on sattunut Esimerkiksi GUI-tapahtumat Tapahtuman käsittelijä (event handler) on koodin osa, joka suoritetaan vastaavan tapahtuman ilmetessä Saadaan ohjelma vastaamaan käyttäjän toimenpiteisiin -> tapahtumaohjattu ohjelmointi Muistuttaa poikkeusten käsittelyä 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 25
VIII.4.1 Tapahtumien käsittely Javassa Tapahtumien kuuntelijat (event listeners) liittää Javassa tapahtumat niiden käsittelijöihin Rekisteröinti: Saatetaan kuuntelija kuuntelemaan jotain määrättyä tapahtumaa Tapahtuu kutsumalla tarkkailtavan olion sopivaa metodia Kuuntelijan on toteutettava metodi, joka käsittelee tapahtuman Luokan toteutettava tapahtumia vastaava rajapinta, jos sitä aiotaan käyttää tapahtuman käsittelijänä 815338A Ohjelmointikielten periaatteet, Poikkeukset ja tapahtumat 26