Javassa poikkeuksia siepataan muodostamalla try/catch/finally -lohko, jonka syntaksi on muotoa
try {
// ohjelmakoodia..
}
catch (Poikkeus e1) {
// lauseet, jotka suoritetaan jos tämä poikkeus tapahtuu
}
catch (Poikkeus e2) {
}
...
finally {
// Lauseet, jotka suoritetaan lopuksi
}
try-lohkossa suoritetaan ne ohjelmalauseet, joissa poikkeuksia voi tapahtua. Jos jokin try-lohkon sisältämistä
lauseista aiheuttaa poikkeuksen, joka kuuluu catch-lauseessa määritellyyn luokkaan, niin tällöin try-lohkon loppuosan
lauseita ei enää suoriteta vaan siirrytään catch-lohkoon, jonka lauseet suoritetaan. finally-lohko suoritetaan
lopuksi huolimatta siitä tapahtuiko mikään poikkeus.
Poikkeusten välittäminen eteenpäin onnistuu throws -sanaa otsikossa ja mainitsemalla välitettävän
poikkeuksen nimi.
void metodi(int i) throws MyException
Jos välitettäviä poikkeuksia esiintyy metodissa useampia niin ne kaikki on mainittava otsikossa
void metodi2(int i) throws MyException, MyAnotherException
Javassa voi ohjelmoida myös omia poikkeusluokkia, jos valmiit luokat eivät riitä. Kaikki poikkeukset
on johdettu Throwable-luokasta, joka haarautuu kahteen haaraan: Exception ja Error. Error-hierarkiassa
olevien luokkien käyttö on harvinaisempaa koska niillä käsitellään Javan ajonaikaisessa järjestelmässä
tapahtuvia virheitä tai resurssien loppumista. Lähteen [1] mukaan poikkeukset jaetaan kahteen luokkaan:
- Poikkeuksiin, jotka on johdettu RuntimeException -luokasta ja
- muihin poikkeuksiin.
RuntimeException -luokasta johdetut poikkeukset johtuvat karkeasti ottaen ohjelmointivirheistä. Muut
poikkeukset johtuvat muista virheistä (esim. tulostusvirheet, syöttövirheet jne.). Java-kielen määrittelyssä
kutsutaan jokaista Error- tai RuntimeException-luokasta johdettua poikkeusta tarkistamattomaksi poikkeukseksi.
Kaikki muut poikkeukset ovat tarkistettuja [1].
Poikkeuksia ei tulisi käyttää sellaisissa tapauksissa, missä asian voi hoitaa muulla tavalla. Mm. taulukon
rajojen ylittämisen tarkistus on tällainen.
void tulostaAlkio(int indeksi) throws ArrayIndexOutOfException { ... }
Sen sijaan ne ovat käyttökelpoisia mm. tiedostosta tai tietokannasta
lukemiseen, missä voi tapahtua virhetilanne lukutilanteessa.
public Image haeKuva(String tiedostonimi) throws IOException { ... }
Poikkeusten käyttäminen on myös virhekoodeja parempi tapa ilmoittaa eri virheistä - virhekoodien
käyttö ei edes ole ominaista olio-ohjelmoinnille. Poikkeuksia tulisi välittää eteenpäin siinä tapauksessa
jos niille ei osata tehdä mitään. Ja siepata ne poikkeukset mitä osataan käsitellä.
Kirjassa [1] on esitelty muutamia vihjeitä siitä kuinka poikkeuksia tulisi käyttää
- Poikkeustenkäsittelyn ei ole tarkoitus korvata yksinkertaista testiä
-Testin toteutus poikkeusten avulla voi usein aiheuttaa huomattavasti hitaammin ajettavaa
koodia, kuin että testin tekisi muulla tavoin.
- Älä käsittele poikkeuksia liian tarkasti
-Poikkeusten käsittely liian tarkasti johtaa ohjelman koon paisumiseen ja koodin tulkinta
on vaikeampaa. Parempi on koota joukko poikkeuksia yhteen try-lohkoon, kuin käsitellä jokaista
omassa lohkossaan.
- Älä tukahduta poikkeuksia
-Jos uskot poikkeusten olevan tärkeitä, sinun on pyrittävä käsittelemään ne asianmukaisesti.
- Poikkeusten käyttäminen ei ole häpeällistä
-Monet ohjelmoijat pyrkivät sieppaamaan jokaisen poikkeuksen vaistonomaisesti. Monissa tilanteissa
olisi parempi välittää poikkeus eteenpäin.
Viitteet:
[1] Core Java 2 - Horstmann, Cornell