Poikkeuskäsittely Mitä poikkeuskäsittely tarkoittaa? Poikkeuskäsittelyluokkien hierakkia Poikkeuksen sieppaaminen Mihin järjestykseen try-catch-lauseen ExceptionType-poikkeukset laitetaan? Poikkeuksen heittäminen ja kiinniottaminen
Mitä poikkeuskäsittely tarkoittaa? Ohjelman suorituksen aikana tapahtuva virhe ohjelma kaatuu esim. pyydetään käyttäjältä kokonaislukua mutta käyttäjä antaa kirjaimia, pyydetään desimaalilukua desimaalipilkuin varustettuna, käyttäjä kirjoittaa desimaaliluvun desimaalipisteellä Ratkaisu: poikkeuskäsittely Joissain tilanteissa kääntäjä vaatii ohjelmaan poikkeuskäsittelyn esim. Kun ohjelma lukee/kirjoittaa tekstiä tiedostoon, ohjelmaan on määriteltävä, mitä tehdään ongelman ilmetessä On myös tilanteita, jossa kääntäjä ei vaadi erikoistoimenpiteitä, mutta jotka saattavat aiheuttaa ohjelman suoritusaikaisen virheen, esim. int luku = Integer.parseInt( kolme ); 2
Poikkeuskäsittelyluokkien hierakkia Vakavat peruttamattomat virheet, joihin ohjelmoija ei aina voi vaikuttaa Esim. Muistin loppuminen ohjelman suorituksen aikana Trowable Error Exception Ohjelmointivirheet ja ohjelman suoritusaikaiset virheet Esim. Viitataan taulukon rakojen ulkopuolelle IOException Tilanteet, joita ohjelmoija ei välttämättä tiedä etukäteen, mutta ne on huomioitava ohjelmakoodissa. Esim. yritys lukea tiedoston lopun yli, yritys hakea verkosta olematonta resurssia. RuntimeException 3
Poikkeuskäsittelyluokkien hierakkia jatkuu : RuntimeException IndexOutOfBoundsException IllegalArgumentException NullPointerException ArithmeticException NumberFormatException ArrayIndexOutOfBounds- Exception 4
Poikkeuksen sieppaaminen try/catch-lause poikkeusten käsittely hoidetaan try/catch-lauseella, jolloin erityyppiset virheet voidaan halutessa tunnistaa try { // lauseet, jotka saattavat aiheuttaa poikkeuksia catch (ExceptionType1 poikkeus1) { // lauseet ExceptionType1 poikkeuksen korjaamiseen catch (ExceptionTYpe2 poikkeus2) { // lauseet ExceptionType2 poikkeuksen korjaamiseen // tänne tullaan poikkeustilanteessa catch-lohkosta // tai // try-lohkosta, kun poikkeuskäsittelyä ei ole tarvinnut tehdä 5
Poikkeuksen sieppaaminen jatkuu Jos jokin try-lohkon lauseista aiheuttaa poikkeuksen, joka kuuluu johonkin catch-lohkoissa määriteltyyn ExceptionType luokkaan: - try-lohkon loppuosa jää suorittamatta - Siirrytään ko. catch-lohkooon ja suoritettaan lohkon lauseet - jatketaan catch-lohkojen jälkeen olevasta lauseesta Jos try-lohkon mikään lause ei aiheuta poikkeusta: - suoritetaan try-lohko loppuun, - sivutetaan kaikki catch-lohkot - jatketaan catch-lohkojen jälkeen olevasta lauseesta 6
Mihin järjestykseen try-catch-lauseen ExceptionTypepoikkeukset laitetaan? Mitä korkeammalla periytymishierarkiaa poikkeus on, sitä laajempi vaikutus sillä on Ensin tulee periytymishierakian alimmat poikkeukset sitten vasta ylimmät 7
public void aja() { Voiko merkkijonon muuttaa kokonaisluvuksi? Jos ei, lause heittää NumberFormat Exceptionpoikkeuksen Esim. int kluku = 0; double dluku = 0; String mjono = null; try { System.out.println( Anna desimaaliluku: "); dluku = input.nextdouble(); //KRIITTINEN LAUSE mjono = "" + dluku; kluku = Integer.parseInt(mjono); //KRIITTINEN LAUSE catch (NumberFormatException e1) { System.out.println(mjono + " ei ole kokonaisluku!"); catch (Exception e2) { nextdouble-metodi aiheuttaa seuraavat poikkeukset: InputMismatch-Exception tai NoSuchElement-Exception tai IllegalState-Exception System.out.println("et antanut desimaalilukua + pilkulla varustettuna!!!!"); input.nextline(); // tyhjennä syöttöpuskuri 8
Esim. public class KymmenenLukua { private Scanner input ; private ArrayList <Integer> kluvut ; private ArrayList <Double> dluvut; private final int LKM = 5; public KymmenenLukua() { input = new Scanner (System.in); kluvut = new ArrayList<Integer>(); dluvut = new ArrayList<Double>(); public void aja() { luedesimaaliluvut(); luekokonaisluvut(); tulostaluvut(); 9
Esim. jatkuu private void luedesimaaliluvut(){// Lukee 5 desimaalukua int i=0; double apu;; String rivi; while (dluvut!= null && i < LKM) { System.out.print("Anna " + (i+1)+". desimaaliluku: " ); rivi = input.nextline(); rivi = rivi.trim(); try { apu = Double.parseDouble(rivi); //KRIITTINEN LAUSE dluvut.add(apu); i++; catch(exception e){ System.out.println("Anna desimaaliluku numeroina" + " ja desimaalipisteellä"); 10
Esim. jatkuu private void luekokonaisluvut () { // Lukee 5 kokonaislukua int i=0; int apu;; String rivi; while (kluvut!= null && i < LKM){ System.out.print("Anna " + (i+1)+". kokonaisluku: " ); rivi = input.nextline(); rivi = rivi.trim(); try { apu = Integer.parseInt(rivi); //KRIITTINEN LAUSE kluvut.add(apu); i++; catch(exception e){ System.out.println("Anna kokonaisluku numeroina"); 11
Esim. jatkuu.. private void tulostaluvut() { // tulostaa taulukon luvut muodossa int i=0; // 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 int apu; System.out.print("Antamasi desimaalluvut ovat: "); while (i < dluvut.size() - 1) { System.out.print(dluvut.get(i) + ", "); i++; System.out.println(dluvut.get(i)); // tulosta viimeinen luku System.out.print("Antamasi kokonaisluvut ovat:"); Iterator<Integer> it = kluvut.iterator(); while (it.hasnext()) { apu = it.next(); if (it.hasnext()) // onko kyseessä viimeinen alkio? System.out.print(apu + ", "); // EI else System.out.println(apu); // ON 12
Esim. jatkuu tulostuu: Anna 1. desimaaliluku: 4,5 Anna desimaaliluku numeroina ja desimaalipisteellä Anna 1. desimaaliluku: 4.5 Anna 2. desimaaliluku: kolme Anna desimaaliluku numeroina ja desimaalipisteellä Anna 2. desimaaliluku: 3 Anna 3. desimaaliluku: 5.7 Anna 4. desimaaliluku: 23.5 Anna 5. desimaaliluku: 1.6 Anna 1. kokonaisluku: 5.6 Anna kokonaisluku numeroina Anna 1. kokonaisluku: 5 Anna 2. kokonaisluku: kolme Anna kokonaisluku numeroina Anna 2. kokonaisluku: 3 Anna 3. kokonaisluku: 0 Anna 4. kokonaisluku: -2 Anna 5. kokonaisluku: 3 Antamasi desimaaliluvut ovat: 4.5, 3.0, 5.7, 23.5, 1.6 Antamasi kokonaisluvut ovat: 5, 3, 0, -2, 3 13
Tuntitehtävä Tee ohjelma PalkkaOhjelma.java, joka pyytää 5 palkkaa ja tulostaa palkkojen keskiarvon. Ohjelmaa pyytää palkkoja varautuen käyttäjän antamiin virheellisiin arvoihin. 14
printstacktrace() Throwable-luokan metodi tulostaa poikkeustilanteessa pinon sisällön Seuraavat lauseet sieppaavat minkä tahansa poikkeuksen: try { // lauseet jotka saattavat aiheuttaa poikkeuksia catch (Exception e) { e.printstacktrace(); 15
public class Esimerkki{ public void aja() { printstacktrace() jatkuu Scanner input = new Scanner (System.in); int luku1, luku2; String mjono; try { System.out.print ("Anna 1. luku: "); mjono = input.nextline(); luku1 = Integer.parseInt(mjono); // KRIITTINEN LAUSE System.out.print ("Anna 2. luku: "); mjono = input.nextline(); luku2 = Integer.parseInt(mjono);// KRIITTINEN LAUSE System.out.println (luku1 / luku2); // KRIITTINEN L catch (Exception e){ System.out.println("\n***VIRHE***"); e.printstacktrace(); 16
Ohjelman suoritus 1.suorituskerta Anna 1. luku: ensimmäinen ***VIRHE*** java.lang.numberformatexception: For input string: "ensimmäinen" at java.lang.numberformatexception.forinputstring(unknown Source) at java.lang.integer.parseint(unknown Source) at java.lang.integer.parseint(unknown Source) at luku9.esimerkki.aja(esimerkki.java:16) at luku9.esimerkki.main(esimerkki.java:34 2. suorituskerta Anna 1. luku: 2 Anna 2. luku: 0 ***VIRHE*** java.lang.arithmeticexception: / by zero at luku9.esimerkki.aja(esimerkki.java:22) at luku9.esimerkki.main(esimerkki.java:34) 17
Tuntitehtävä Tee ohjelma, Poikkeuskokeilu, joka pyytää käyttäjältä kokonaisluvun, lukee luvun Scanner-luokan nextint-metodin avulla ja tulostaa luvun. Jos käyttäjä antaa kokonaisluvun tilalle kirjaimia tai desimaaliluvun, ohjelma ilmoittaa virheen poikkeuksen printstacktrace-metodin avulla. Kokonaisluvun lukemisen jälkeen ohjelma pyytää desimaaliluvun ja lukee sen Scanner-luokan nextdouble-metodin avulla ja tulostaa luvun. Jos käyttäjä antaa desimaaluvun tilalle kirjaimia tai desimaaliluvun desimaalipisteellä, ohjelma ilmoittaa virheen poikkeuksen printstacktrace-metodin avulla. 18
Poikkeuksen heittäminen ja kiinniottaminen Poikkeus voidaan heittää luomalla poikkeusolio ja heittämällä se lauseella throw poikkeus Metodi voi heittää poikkeuksen, mikä edellyttää sitä, että kutsuja ottaa poikkeuksen kiinni eli metodin kutsu pitää olla try-catch-lauseessa try:n sisällä Jos metodi heittää poikkeuksen se on esiteltävä seuraavasti: näkyvyys paluu metodinimi(parametrit) throws poikkeus 1, poikkeus 2,...,poikkeus n 19
Poikkeuksen heittäminen esimerkki public class PoikkeuksenHeitto { private Scanner input; public PoikkeuksenHeitto(){ input = new Scanner (System.in); private int pyydaluku () throws Exception { int luku = 0; System.out.println("Anna kokonaisluku, ei nolla: "); try{ luku = input.nextint(); // KRIITTINEN LAUSE if (luku ==0) throw new Exception(); // luku!= 0 luo poikkeus ja heitä se catch (Exception e){ input.nextline(); throw e; return luku; // tyhjennä syöttöpuskuri // heitä poikkeus eteenpäin 20
Poikkeuksen heittäminen esimerkki jatkuu. public void aja() { boolean ok = true; int luku=0; do { try { luku =pyydaluku(); // KRIITTINEN LAUSE ok=true; catch (Exception e) { System.out.println("Anna numeroita (> 0)!"); ok =false; while (ok == false); System.out.println("annoit " + luku); 21
Poikkeuksen heittäminen esimerkin toteutus tulostuu: Anna kokonaisluku, ei nolla: kolme Anna numeroita! Anna kokonaisluku, ei nolla: 0 Anna numeroita! Anna kokonaisluku, ei nolla: 3 annoit 3 22
Tuntitehtävä: Muokkaa ohjelmaa LaskeJaTulostakertotaulu. Lisää ohjelman metodiin lueluku() poikkeuskäsittely, eli kun käyttäjä antaa kelvottoman kokonaisluvun, metodi heittää poikkeuksen metodin kutsujalle. Kutsuja ilmoittaa virheestä ja pyytää uutta kokonaislukua (lueluku-metodin kutsu), kunnes saa kelvollisen. 23