Fehler und Ausnahmen in Java 7. Java Fehler und Ausnahmen Fehler und Ausnahmen unterbrechen die normale Programmausführung abrupt und stellen eine nicht geplantes Ereignis dar. 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 186 Fehler (Errors) Ausnahmen (Exceptions) Fehler treten in der virtuellen Machine von Java auf und sind nicht reparierbar. Kein Speicher mehr verfügbar Zu hoher Aufrufstapel ( Rekursion) Fehlende Programmbibliotheken Bug in der virtuellen Machine Ausnahmen werden von der virtuellen Machine oder vom Programm selbst ausgelösst und können meist behandelt werden um die Normalsituation wiederherzustellen Dereferenzierung von null Division durch 0 Schreib/Lesefehler (Dateien) Hier ist nichts mehr zu machen Computer-Hardwarefehler Aufwischen und neu einschenken Businesslogik Fehler 187 188
Arten von Ausnahmen Systemausnahmen (runtime exceptions) Können überall auftreten Können behandelt werden Ursache: Bug im Programm Benutzerausnahmen (checked exceptions) Müssen deklariert werden Müssen behandelt werden Ursache: Unwahrscheinliches, aber prinzipiell mögliches Ereignis Beispiel einer Systemausnahme 1 import java. util. Scanner; 2 class ReadTest { 3 public static void main(string[] args){ 4 int i = readint("zahl"); 5 6 private static int readint(string prompt){ 7 System.out.print(prompt + ": "); 8 Scanner input = new Scanner(System.in); 9 return input.nextint (); 10 11 Eingabe: Zahl: asdf 189 190 Nicht behandelte Fehler und Ausnahmen 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 ReadTest.main(); 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) ReadTest.main ReadTest.readInt int i = readint("zahl"); return input.nextint(); Forensische Nachforschungen mit Hilfe dieser Information. Scanner.nextInt 191 192
Stacktraces verstehen Stacktraces verstehen Ausgabe: Eine unpassende Eingabe 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) aufgerufen durch Methode main auf Zeile 4. in Methode readint auf Zeile 9 193 1 import java. util. Scanner; 2 class ReadTest { 3 public static void main(string[] args){ 4 int i = readint("zahl"); 5 6 private static int readint(string prompt){ 7 System.out.print(prompt + ": "); 8 Scanner input = new Scanner(System.in); 9 return input.nextint (); 10 11 at ReadTest.readInt(ReadTest.java:9) at ReadTest.main(ReadTest.java:4) 194 Systemausnahme: Bug im Programm?! Intermezzo: Optionale Datentypen Wo ist der Fehler? private static int readint(string prompt){ System.out.print(prompt + ": "); Scanner input = new Scanner(System.in); return input.nextint(); Nicht garantiert, dass als nächstes ein int anliegt. Die Scanner Klasse bietet ein Test dafür an Optionale Datentypen ermöglichen guten Stil Java bietet Klassen (Datentypen) an um optionale Werte explizit darzustellen. : Für int OptionalInt Für double OptionalDouble Für String Optional<String> (generic, kommt später) Warum optionale Typen: Aufrufer/Benutzer kann selber entscheiden, wann und wie mit abwesenden Werten umgegangen werden soll, dies ohne Ausnahmen zu werfen. 195 196
API von OptionalInt Erstellen eines optionalen ints: Falls eine Zahl vorhanden ist: i = 5; OptionalInt opt_i = OptionalInt.of(i ); //Wert wird eingepackt Falls keine Zahl vorhanden ist: OptionalInt opt_i = OptionalInt.empty(); //Ein leerer Wert API von OptionalInt Benutzung von OptionalInt opt_i: Einen Standardwert wählen, falls leer: int i = opt_i.orelse( 1); Explizit prüfen ob eine Zahl vorhanden ist: if (opt_i.ispresent()){ int i = opt_i.getasint(); 197 198 Guter Code: Erst prüfen, optionales Resultat private static OptionalInt readint(string prompt){ System.out.print(prompt + ": "); Entweder ein int oder leer Scanner input = new Scanner(System.in); if (input.hasnextint()){ return OptionalInt.of(input.nextInt()); else { input.next(); // consume the wrong token return OptionalInt.empty(); Testet ob ein int am Input anliegt. Resultat in OptionalInt einpacken Die aufrufende Methode kann entscheiden, was dann passiert Mögliche Behandlung von optionalen Datentypen import java. util. OptionalInt; 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(); 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. Kinder kippen Becher um. Man gewöhnt sich daran. 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); 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 ^ 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 206 Behandeln von Ausnahmen private static String[] readfile(string filename){ try{ FileReader fr = new FileReader(filename); BufferedReader bufr = new BufferedReader(fr); catch (IOException e){ // do some recovery handling finally { // close resources Geschützter Bereich Massnahmen zur Wiederherstellung der Normalsituation Wird in jedem Fall am Schluss ausgeführt, immer! Behandlung von Ausnahmen: Propagieren stoppen! Java VM Runtime ReadTest.main ReadTest.main(); ReadTest.readFile Exception caught! BufferedReader.readLine lines = readfile("dataset.csv"); 207 208
Finally: Resourcen schliessen! In Java müssen Resourcen unbedingt geschlossen werden nach Gebrauch. Ansonsten wird Speicher nicht freigegeben. Resourcen: Dateien Datenströme GUI Elemente... Try-with-resources Anweisung Spezifische Syntax an, um Ressourcen automatisch zu schliessen: private static String[] readfile(string filename){ try ( FileReader fr = new FileReader(filename); BufferedReader bufr = new BufferedReader(fr)) { catch (IOException e){ // do some recovery handling Resourcen werden hier geöffnet Resourcen werden hier automatisch geschlossen 209 210