Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Håndtering av avbrudd – unntak og feil JavaGently kap. 4.4 © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-1 Sett slikt ! ? 1: class Testunntak { 2: public static void main ( String [ ] args ) { 3: new Testunntak ( args ); 4: } 5: Testunntak ( String [] args ) { 6: System.out.println ( args[0] ); 7: int m = 3, k = Integer.parseInt( args[1]); 8: int n = 2/(m-k); 9: } 10:} ...>java Testunntak Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 at Testunntak.<init><Testunntak.java:6> at Testunntak.main<Testunntak.java:3> ...>java Testunntak tull 3 tull Exception in thread "main" java.lang.ArithmeticException: / by zero at Testunntak.<init><Testunntak.java:8> at Testunntak.main<Testunntak.java:3> © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-2 Hvordan håndtere det unormale o Det hender at et program kommer i en unormal situasjon, eksempelvis o Divisjon med 0 o Indeksering av en tabell eller tegnstreng utenfor "kanten" o Konvertering til tall av en feilaktig tekststreng o Forsøk på å følge en null-peker o Det er et ønskemål at programmeringen av det unormale ikke forkludrer programmeringen av det normale o Programlogikken bør vise den normale kontrollflyten o Unormale situasjoner bør tas hånd om av spesialkonstruksjoner i programmeringsspråket © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-3 Håndtering av det unormale i Java o Når Java (mer nøyaktig: JVM) kommer opp i en unormal situasjon, genereres ("kastes") et avbrudds-objekt ("en varm potet") o Dette objektet inneholder opplysninger om årsaken til avbruddet, og om på hvilket sted i programmet det skjedde o Avbrudd kan være enten o Unntak ("Exception") » Aritmetiske feil, indeksfeil, bruk av null-pekere, … » Feil under inn-ut-operasjoner, tilknytning til filer … o Error » Grusomme systemfeil vi ikke kan gjøre noe særlig med © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-4 Håndtering av unntak o Metoden som forårsaket unntaket kan o enten selv ta hånd om avbrudds-objektet og prøve å rette opp situasjonen o eller avslutte utførelsen og "kaste" avbrudds-objektet opp til kallende metode ("exception propagation") o eller la være å gjøre noe som helst o Hvis en metode som får "den varme poteten" unnlater å gjøre noe, vil programmet terminere med en feilmelding Vi diskuterer heretter bare unntak – "errors" kan vi jo ikke gjøre noe med… © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-5 Hvordan fange opp avbrudd o Ta imot dem / ‘fange’ dem: try{ ... farlig kode.... } catch ( Exception e) { ... gjør noe fornuftig fordi ‘feil har oppstått.. } //end try o Ta imot dem, gjøre noe og så kaste dem videre oppover: try{ ... farlig kode.... } catch ( Exception e) { ... gjør noe fornuftig fordi ‘feil har oppstått.. throw e; Alle unntak er objekter av klassen Exception } //end try (eller subklasser av denne) © Institutt for informatikk – Gerhard Skagestein Stein Gjessing IN105-javaunntak-6 Eksempel på ikke oppfanget feil 1: class Unntak0 { 2: public static void main(String[ ] args) { 3: new Unntak0 ( ) ; } 4: Unntak0 ( ) { 5: int dividend=7, divisor = 0; int kvotient; 6: kvotient = dividend/divisor; 7: System.out.println(kvotient); 8: } 9: } >java Exception0 .... Java.lang.ArithmeticException: / by zero at Unntak0.<init>(Unntak0.java: 6) at Unntak0.main(Unntak0.java: 3) © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-7 Enda et eksempel på ikke oppfanget feil class Unntak1 { public static void main(String[ ] args) { new Unntak1 ( ) ; } Unntak1 ( ) { String s="Dette er en tekst med 29 tegn"; String s1; s1 = s.substring(30,32); // string-indeks utenfor "enden" System.out.println(s1); } } >java Unntak1 ...java.lang.StringIndexOutOfBoundsException: String index out of range: 32 at java.lang.String.substring(String.java:1486) at Unntak1.<init>(Unntak1.java:5) at Unntak1.main(Unntak1.java: 2) © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-8 Vi fanger unntaket class Unntak1a { public static void main(String[ ] args) { new Unntak1a ( ); } Unntak1a ( ) { String s="Dette er en tekst med 29 tegn"; String s1; try { s1 = s.substring(30,32); // string-indeks utenfor "enden" } catch (StringIndexOutOfBoundsException e) { System.out.println("Her er det noe galt med string-indeksen"); s1 = "*********"; } //end try System.out.println(s1); } } >java Unntak1a Her er det noe galt med string-indeksen ********* © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-9 Vi fanger unntaket, men sender det videre class Unntak1b { public static void main(String[ ] args) { new Unntak1b ( ); } Unntak1b ( ) { String s="Dette er en tekst med 29 tegn",s1; try { s1 = s.substring(30,32); // string-indeks utenfor "enden" } catch (StringIndexOutOfBoundsException e) { System.out.println("Her er det noe galt med string-indeksen"); throw e; //kast unntaket videre } //end try System.out.println(s1); } } >java Unntak1b Her er det noe galt med string-indeksen Java.lang.StringIndexOutOfBoundsException: String index out of range: 32 at java.lang.String.substring(String.java:1486) at Unntak1b.<init>(Unntak1b.java: 6) at Unntak1b.main(Unntak1b.java: 2) © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-10 A Skisse unntaksbehandling Skisse avavunntaksbehandling B try { A kaller B } catch (Unntaksklasse unt) { < Unntaksbehandling. Dette hoppes over når intet unormalt har hendt > } < her fortsetter vanligvis programmet både etter normal utføring og etter behandling av eventuelle unntak > B oppdager en feil: throw new Unntaksklasse ( ) ; Normal retur fra B til A Unntaksklasse er en forhåndsdeklarert subklasse av klassen Exception. Dette kommer vi tilbake til. JavaGently Figur 4.6 – side 115 © Institutt for informatikk – Gerhard Skagestein Stein Gjessing IN105-javaunntak-11 Utskrift av detaljer om unntaket class Unntak1c { public static void main(String[ ] args) { new Unntak1c ( ); } Unntak1c ( ) { String s = "Dette er en tekst med 29 tegn", s1; try { s1 = s.substring(30,32); // string-indeks utenfor "enden" } catch (StringIndexOutOfBoundsException e) { System.out.println("Her er det noe galt med string-indeksen " + e.getMessage( )); s1 = "*********"; } //end try System.out.println(s1); } } >java Unntak1c Her er det noe galt med string-indeksen String index out of range: 32 ********* © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-12 Tilordninger i try-blokken utføres ikke alltid class Unntak1c { public static void main(String[ ] args) { new Unntak1c ( ); } Unntak1c ( ) { String s = "Dette er en tekst med 29 tegn", s1; try { s1 = s.substring(30,32); // string-indeks utenfor "enden" } catch (StringIndexOutOfBoundsException e) { System.out.println("Her er det noe galt med string-indeksen "); // s1 = "*********"; } //end try System.out.println(s1); } } ...> javac Unntak1c.java Unntak1c.java:15: Variable s1 may not have been initialized. System.out.println(s1); ^ © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-13 Test på flere unntak class Unntak2a { public static void main(String[ ] args) { new Unntak2a ( ) ; } Unntak2a ( ) { int dividend=7, divisor = 0; int kvotient=0; String s="Dette er en tekst med 29 tegn"; String s1="*********"; try { s1 = s.substring(15,17); // OK string-indeks kvotient = dividend/divisor; // divisjon med 0 } catch (StringIndexOutOfBoundsException e) { System.out.println("Her er det noe galt med string-indeksen"); } catch (ArithmeticException e1) { System.out.println("Divisjon med 0: " + e1.getMessage( ) ); } //end try >java Unntaka System.out.println(s1); Divisjon med 0: / by zero System.out.println(kvotient); St 0 } } © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-14 Try – fullstendig utgave Try-setning Try { setninger // farlig kode } catch (Unntaksklasse1 variabel1) { setninger } catch (Unntaksklasse2 variabel 2) { setninger } finally { setninger // disse utføres alltid! } // end try Både catch-leddene og finally-leddet kan utelates! © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-15 Kontrollerte unntak o For en lang rekke av de unntakene som kan kastes av Java API (dvs. klassebiblioteket) gjelder at kompilatoren kontrollerer at de blir tatt hånd om o Eksempelvis gir følgende program kompileringsfeil: import java.io.*; class Unntak3 { Dette programmet skal public static void main(String[ ] args) { new Unntak3 lese ( ); }fra tastaturet – Unntak3 ( ) { mer om det senere… BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); String message; System.out.println("Enter a line of text:"); message = stdin.readLine(); System.out.println("You entered: \" " + message + "\""); } > javac Unntak3 } …\Unntak3.java.9: Exception java.io.IOException must be caught, or it must be declared in the throw clause of this method. message = stdin.readLine(); © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-16 Løsning A – fang unntaket import java.io.*; class Unntak3a { public static void main(String[ ] args) { new Unntak3a ( ); } Unntak3a ( ) { int number = 0; BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Skriv inn et heltall"); try { number = Integer.parseInt (stdin.readLine( )); } catch (IOException e) { System.out.println(e.getMessage( ) + " Avslutter!"); System.exit(0); // Dette kallet terminerer programmet } // end try System.out.println(number); } } © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-17 Løsning B – deklarer at metoden kan kaste unntaket import java.io.*; class Unntak3b { public static void main(String[ ] args) { new Unntak3b ( ) ; } Unntak3b ( ) throws IOException { int number = 0; BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); String message; Hvorfor insisterer Java på System.out.println("Skriv inn et heltall"); dette? number = Integer.parseInt (stdin.readLine( ));Jo, fordi det at en metode kan kaste et unntak er en System.out.println(number); like viktig opplysning for } omgivelsene som selve } signaturen (metodenavn, parametre og returverdier) © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-18 Løsning - fang unntaket til slutt import java.io.*; class Unntak3c { public static void main(String[ ] args) { try { new Unntak3c ( ) ; } catch ( IOException e) { System.out.println (" Det skjedde noe galt ved lesing."); } } Unntak3c ( ) throws IOException { int number = 0; ........ number = Integer.parseInt (stdin.readLine( )); System.out.println(number); } } © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-19 RuntimeExceptions o Kompilatoren krever ikke at alle unntak skal tas hånd om på denne måten o De såkalte RuntimeExceptions (som divisjon med 0, indeks utenfor "kanten", forsøk på å følge en null-peker, forsøk på å konvertere en feilaktig tekststreng til et tall) kan forekomme så mange steder at dette vil være upraktisk – vi må heller forsøke å unngå dem… >java Unntak3c Skriv inn et heltall g67 java.lang.NumberFormatException: g67 at java.lang.Integer.parseInt(Compiled code) at java.lang.Integer.parseInt(Integer.java:458) at Unntak3c.<init>(Unntak3c.java:15) at Unntak3c.main(Unntak3.java:4) © Institutt for informatikk – Gerhard Skagestein Eksempel på RuntimeException ved kjøring av programmet på forrige lysark med ukorrekte inndata IN105-javaunntak-20 Vi slår to fluer i en smekk import java.io.*; class Unntak3d { public static void main(String[ ] args) { new Unntak3d ( ) ; } Unntak3d ( ) { int number = 0; BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); boolean korrekt = false; while (! korrekt) { // gå i løkke inntil brukeren har gitt korrekte inndata System.out.println("Skriv inn et heltall"); try { number = Integer.parseInt (stdin.readLine( )); korrekt = true; } catch (NumberFormatException exception) { System.out.println ("Ukorrekte inndata - skriv inn en gang til..."); } catch (IOException exception) { System.out.println(exception.getMessage( ) + " Avslutter!"); System.exit(0); // Dette kallet terminerer programmet } // end try } // end while System.out.println(number); } } © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-21 Hva skjer når vi kjører Unntak3d ? ...>java Unntak3d Skriv inn et heltall g67 Ukorrekte inndata - skriv inn en gang til ... jsg Ukorrekte inndata - skriv inn en gang til ... 67 67 ...> © Institutt for informatikk – Gerhard Skagestein IN105-javaunntak-22 Lag ditt eget unntak! class Mittunntak extends Exception { public Mittunntak ( ) { } public Mittunntak (String s ) { } // end konstruktører } // end class Mittunntak …. ….. throw new Mittunntak("feilmelding"); © Institutt for informatikk – Gerhard Skagestein Den nye klassen Mittunntak bygger på (extends) en Java APIklasse med navn Exception. Detaljene i dette skal vi komme tilbake til IN105-javaunntak-23