Fehler und Ausnahmen in Java Fehler und Ausnahmen unterbrechen die normale Programmausführung abrupt und stellen eine nicht geplantes Ereignis dar. 7. Java Fehler und Ausnahmen Ausnahmen sind böse, oder doch nicht? Fehler, Systemausnahmen, Benutzerausnahmen, Behandeln von Ausnahmen, Spezialfall Ressourcen Java ermöglicht es, solche Ereignisse abzufangen und zu behandeln (als Alternative zum Programmabsturz). Nicht behandelte Fehler und Ausnahmen werden durch den Aufrufstapel hochgereicht. 185 Fehler (Errors) 186 Ausnahmen (Exceptions) Ausnahmen werden von der virtuellen Machine oder vom Programm selbst ausgelösst und können meist behandelt werden um die Normalsituation wiederherzustellen Fehler treten in der virtuellen Machine von Java auf und sind nicht reparierbar. Beispiele Beispiele Kein Speicher mehr verfügbar Zu hoher Aufrufstapel (→ Rekursion) Dereferenzierung von null Fehlende Programmbibliotheken Division durch 0 Bug in der virtuellen Machine Schreib/Lesefehler (Dateien) Businesslogik Fehler Computer-Hardwarefehler Aufwischen und neu einschenken Hier ist nichts mehr zu machen 187 188 Arten von Ausnahmen Beispiel einer Systemausnahme 1 Systemausnahmen (runtime exceptions) 2 Benutzerausnahmen (checked exceptions) 3 4 5 Können überall auftreten Müssen deklariert werden Können behandelt werden Müssen behandelt werden Ursache: Bug im Programm Ursache: Unwahrscheinliches, aber prinzipiell mögliches Ereignis 6 7 8 9 10 11 import java. util .Scanner; class ReadTest { public static void main(String[] args){ int i = readInt("Zahl"); } private static int readInt(String prompt){ System.out.print(prompt + ": "); Scanner input = new Scanner(System.in); return input.nextInt (); } } Eingabe: Zahl: asdf 189 Nicht behandelte Fehler und Ausnahmen 190 Ausnahme propagiert durch Aufrufstapel Das Programm stürzt ab und hinterlässt auf der Konsole eine “Aufrufstapelzurückverfolgung” (ab jetzt: Stacktrace). Darin sehen wir, wo genau das Programm abgebrochen wurde. Java VM Runtime Exception in thread "main" java. util .InputMismatchException [...] at java . util .Scanner.nextInt(Scanner.java:2076) at ReadTest.readInt(ReadTest.java:9) at ReadTest.main(ReadTest.java:4) 8 int i = readInt("Zahl"); ReadTest.readInt8 8 8 191 ReadTest.main(); ReadTest.main 8 ⇒ Forensische Nachforschungen mit Hilfe dieser Information. = return input.nextInt(); Scanner.nextInt 8 192 Stacktraces verstehen Ausgabe: Stacktraces verstehen Eine unpassende Eingabe ... 1 2 3 Exception in thread "main" java.util.InputMismatchException at java . util .Scanner.throwFor(Scanner.java:864) at java . util .Scanner.next(Scanner.java:1485) at java . util .Scanner.nextInt(Scanner.java:2117) at java . util .Scanner.nextInt(Scanner.java:2076) at ReadTest.readInt(ReadTest.java:9) at ReadTest.main(ReadTest.java:4) 4 5 6 7 8 9 10 11 ... in Methode readInt auf Zeile 9 ... ... aufgerufen durch Methode main auf Zeile 4. import java. util .Scanner; class ReadTest { public static void main(String[] args){ int i = readInt("Zahl"); } private static int readInt(String prompt){ System.out.print(prompt + ": "); Scanner input = new Scanner(System.in); return input.nextInt (); } } at ReadTest.readInt(ReadTest.java:9) at ReadTest.main(ReadTest.java:4) 193 194 Systemausnahme: Bug im Programm?! Intermezzo: Optionale Datentypen Wo ist der Fehler? Java bietet Klassen (Datentypen) an um optionale Werte explizit darzustellen. private static int readInt(String prompt){ System.out.print(prompt + ": "); Scanner input = new Scanner(System.in); return input.nextInt(); } Beispiele: Für int ⇒ OptionalInt Für double ⇒ OptionalDouble Für String ⇒ Optional<String> (generic, kommt später) Nicht garantiert, dass als nächstes ein int anliegt. Warum optionale Typen: Aufrufer/Benutzer kann selber entscheiden, wann und wie mit abwesenden Werten umgegangen werden soll, dies ohne Ausnahmen zu werfen. ⇒ Die Scanner Klasse bietet ein Test dafür an ⇒ Optionale Datentypen ermöglichen guten Stil 195 196 API von OptionalInt API von OptionalInt Benutzung von OptionalInt opt_i: Erstellen eines optionalen ints: Einen Standardwert wählen, falls leer: Falls eine Zahl vorhanden ist: int i = opt_i.orElse(−1); i = 5; OptionalInt opt_i = OptionalInt.of(i ); //Wert wird ’eingepackt’ Explizit prüfen ob eine Zahl vorhanden ist: ... if (opt_i.isPresent ()){ int i = opt_i.getAsInt(); ... } Falls keine Zahl vorhanden ist: OptionalInt opt_i = OptionalInt.empty(); //Ein leerer Wert 197 Guter Code: Erst prüfen, optionales Resultat 198 Mögliche Behandlung von optionalen Datentypen Entweder ein int oder leer import java. util .OptionalInt; private static OptionalInt readInt(String prompt){ System.out.print(prompt + ": "); Scanner input = new Scanner(System.in); Testet ob ein int if (input.hasNextInt()){ return OptionalInt.of(input.nextInt()); am Input anliegt. } else { input.next(); // consume the wrong token Resultat in Opreturn OptionalInt.empty(); tionalInt ein} packen } Standardwert benützen: int x = readInt("x").orElse(0); Nachfragen bis es stimmt: OptionalInt opt_x; while (!( opt_x = readInt("x")).isPresent()){ System.out.println("Please enter an integer " ); } int x = opt_x.getAsInt(); Die aufrufende Methode kann entscheiden, was dann passiert 199 200 Erste Erkenntnis: Oft keine Ausnahmesituation Zweite Erkenntnis: Ausnahmen verhindern Oft sind die “Sonderfälle” gar kein besonderes Ereignis, sondern absehbar. Hier sollten keine Ausnahmen verwendet werden! Statt eine Systemausnahme abzuwarten aktiv verhindern, dass diese überhaupt auftreten kann. Beispiele Kinder kippen Becher um. Man gewöhnt sich daran. Beispiele Falsche Credentials beim Einloggen Usereingaben frühzeitig prüfen Leere Pflichtfelder in Eingabemasken Optionale Typen verwenden Nicht verfügbare Internet-Ressourcen Timeout Situationen voraussehen Timeouts Problem gelösst. Plan B für nicht verfügbare Ressourcen 201 202 Arten von Ausnahmen Beispiel einer Benutzerausnahme Systemausnahmen (runtime exceptions) private static String[] readFile(String filename){ FileReader fr = new FileReader(filename); BufferedReader bufr = new BufferedReader(fr); ... line = bufr.readLine(); ... } Benutzerausnahmen (checked exceptions) Können überall auftreten Müssen deklariert werden Können behandelt werden Müssen behandelt werden Compiler Fehler: Ursache: Bug im Programm Ursache: Unwahrscheinliches, aber prinzipiell mögliches Ereignis ./Root/Main.java:9: error: unreported exception FileNotFoundException; must be caught or declared to be t FileReader fr = new FileReader(filename); ^ ./Root/Main.java:11: error: unreported exception IOException; must be caught or declared to be thrown String line = bufr.readLine(); ^ 2 errors 203 204 Kurzer Blick in die Javadoc Warum eine Benutzerausnahme? Situation rechtfertigt die Benutzerausnahme: Fehlerfall ist unwahrscheinlich aber prinzipiell möglich – und kann durch geeignete Massnahmen zur Laufzeit behoben werden können. Der Aufrufer einer Methode mit einer deklarierten Benutzerausnahme wird gezwungen, sich damit zu beschäftigen – behandeln oder weiterreichen. 205 Behandeln von Ausnahmen 206 Behandlung von Ausnahmen: Propagieren stoppen! private static String[] readFile(String filename){ try{ FileReader fr = new FileReader(filename); BufferedReader bufr = new BufferedReader(fr); Geschützter ... Bereich line = bufr.readLine(); ... } catch (IOException e){ Massnahmen zur Wiederher// do some recovery handling stellung der Normalsituation } finally { // close resources Wird in jedem Fall am } Schluss ausgeführt, immer! } ReadTest.main(); Java VM Runtime ReadTest.main lines = readFile("dataset.csv"); ReadTest.readFile 4 line = bufr.readLine(); Exception caught! 8 207 BufferedReader.readLine 8 208 Finally: Resourcen schliessen! Try-with-resources Anweisung Spezifische Syntax an, um Ressourcen automatisch zu schliessen: In Java müssen Resourcen unbedingt geschlossen werden nach Gebrauch. Ansonsten wird Speicher nicht freigegeben. private static String[] readFile(String filename){ try ( FileReader fr = new FileReader(filename); BufferedReader bufr = new BufferedReader(fr)) { ... line = bufr.readLine(); ... Resourcen wer} catch (IOException e){ den hier geöffnet // do some recovery handling } Resourcen werden hier automatisch geschlossen } Resourcen: Dateien Datenströme GUI Elemente ... 209 210