Prof. Dr. Oliver Haase Karl Martin Kern Achim Bitzer Programmiertechnik Ausnahmen Motivation ● Anwendungsbeispiel 1: Konsole java Excep1 a: 15 b: 3 a/b=5 Job done. ● Anwendungsbeispiel 2: Konsole java Excep1 a: 15 b: 0 java.lang.ArithmeticException: / by zero at Excep1.doYourJob(Excep1.java:7) Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 2/27 Motivation ● ● ● Unter bestimmten Umständen kann das Programm nicht ordnungsgemäß beendet werden, sondern liefert einen Fehler und bricht ab. Es gibt eine Vielzahl möglicher Fehlerquellen: ● arithmetische Operationen (Division durch 0, …) ● Zugriff auf Datei, die nicht existiert ● Schreibzugriff auf schreibgeschützte Datei ● Festplattenschaden ● Programm lädt Daten aus dem Internet herunter, Kommunikationsverbindung bricht ab. ● … Diese Vorlesung handelt davon, wie man in Java-Programmen mit solchen Fehlersituationen umgeht. Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 3/27 Ansätze zur Fehlerbehandlung ● ● In älteren Programmiersprachen (z.B. in C) verwendet man die Funktionsrückgabewerte, um fehlerhafte Funktionsausführung anzuzeigen → integrierte Fehlerbehandlung Das Fehlschlagen einer Funktion wird dabei üblicherweise durch einen negativen Rückgabewert angezeigt. Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 4/27 Integrierte Fehlerbehandlung ● C-Stil Fehlerbehandlung in Java: public public class class Excep2 Excep2 {{ public public int int doYourJob() doYourJob() {{ Scanner Scanner scanner scanner == new new Scanner(System.in); Scanner(System.in); System.out.print("a: System.out.print("a: "); "); int int aa == scanner.nextInt(); scanner.nextInt(); System.out.print("b: System.out.print("b: "); "); int int bb == scanner.nextInt(); scanner.nextInt(); }} if if (( bb == == 00 )) return return -1; -1; System.out.println("a System.out.println("a // bb == "" ++ a/b); a/b); return return 0; 0; Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 5/27 Integrierte Fehlerbehandlung }} public public static static void void main(String[] main(String[] args) args) {{ int int ret; ret; Excep2 Excep2 instance instance == new new Excep2(); Excep2(); if if (( (( ret ret == instance.doYourJob() instance.doYourJob() )) << 00 )) System.out.println("Fehlercode: System.out.println("Fehlercode: "" ++ ret); ret); else else System.out.println("Job System.out.println("Job done."); done."); }} Konsole java Excep2 a: 15 b: 0 Fehlercode: -1 Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 6/27 Integrierte Fehlerbehandlung ● Integrierte Fehlerbehandlung hat mehrere Nachteile: ● verschiedene Fehlerwerte für verschiedene Funktionen, manchmal bedeutet 0 Fehler, manchmal -1, manchmal jeder negative Wert… ● Aufrufer muss wissen, welchen Wert Funktion im Fehlerfall liefert ● Fehlerbehandlung integriert in "regulären" Code → schwer lesbar ● ● Fehler sollten die Ausnahme sein → unnatürlich, den Rückgabewert einer Funktion dem Fehlerfall zu widmen Wenn eine Funktion tatsächlich einen Wert liefern soll, muss entweder dieser Wert oder der Fehlercode innerhalb eines Referenztypparameters zurückgegeben werden. Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 7/27 Fehlercode als Referenzparameter ● Beispiel: Angenommen, die Methode doYourJob druckt das Ergebnis der Division a/b nicht aus, sondern liefert es als Ergebniswert zurück: public public class class Excep3 Excep3 {{ public public int int doYourJob(int doYourJob(int a, a, int int b, b, int[] int[] error) error) {{ }} if if (( bb == == 00 )) {{ error[0] error[0] == -1; -1; return return -1; -1; }} error[0] error[0] == 0; 0; return return a/b; a/b; Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 8/27 Fehlercode als Referenzparameter }} public public static static void void main(String[] main(String[] args) args) {{ Scanner Scanner scanner scanner == new new Scanner(System.in); Scanner(System.in); System.out.print("a: "); System.out.print("a: "); int int aa == scanner.nextInt(); scanner.nextInt(); System.out.print("b: System.out.print("b: "); "); int int bb == scanner.nextInt(); scanner.nextInt(); Excep3 Excep3 instance instance == new new Excep3(); Excep3(); int[] error = new int[1]; int[] error = new int[1]; int int ret ret == instance.doYourJob(a, instance.doYourJob(a, b, b, error); error); if ( error[0] == -1 ){ if ( error[0] == -1 ){ System.out.println("Fehlercode: System.out.println("Fehlercode: "" ++ error[0]); error[0]); }} else else {{ System.out.println("a System.out.println("a // bb == "" ++ ret); ret); System.out.println("Job System.out.println("Job done."); done."); }} }} Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 9/27 Fehlercode als Referenzparameter ● ● ● Alternative: Statt ein Feld zu verwenden könnte man eine Klasse definieren, die eine int-Komponente für den Errorcode enthält. Fazit: Funktioniert, aber mühsam, unnatürlich und fehleranfällig… Moderne Programmiersprachen, wie z.B. C++ und Java, verwenden Ausnahmen (exceptions) für die Fehlerbehandlung. Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 10/27 Ausnahmen / Exceptions ● ● ● ● Trennung von regulärem Code und Fehlerbehandlung. Wenn eine Ausnahmesituation eintritt – z.B. Division durch 0 – wird ein Exception-Objekt erzeugt und mit Informationen zur Fehlerursache und zum Ort des Auftretens initialisiert. Diese Informationen können über geeignete Instanzmethoden abgerufen werden. Exceptions werden nicht als reguläre Methodenrückgabewerte propagiert, sondern über einen speziellen Exception-Mechanismus. Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 11/27 Ausnahmen / Exceptions ● ● ● In Java ist jedes Exception-Objekt eine Instanz der Klasse java.lang.Exception, oder einer Subklasse davon. Die Fehlerursache kann mit der Instanzmethode public String getMessage() abgerufen werden. Der Ort des Auftretens kann mit der Instanzmethode public String printStackTrace() abgerufen werden. Konsole java Excep1 Exception-Klasse a = 15 getMessage() b=0 java.lang.ArithmeticException: / by zero at Excep1.doYourJob(Excep1.java:10) printStackTrace() Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 12/27 Abfangen von Exceptions ● ● Wenn eine Ausnahmesituation auftritt, wird eine Exception (Ausnahme) geworfen ("to throw an exception"). Exceptions können im Programm abgefangen werden ("to catch an exception"), um ● Abstürze zu vermeiden ● geeignete Fehlerbehandlung durchzuführen, etwa ● Meldung ausgeben (z.B. in einem geeigneten Fenster) ● Aufräumen bevor das Programm ordentlich terminiert wird. Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 13/27 Abfangen von Exceptions ● In Java geschieht dies durch eine Kombination von try und catch Anweisungen: ● ● Anweisungen, die fehlschlagen können, werden mit try eingeklammert; Die Fehlerbehandlung folgt in einem oder mehreren catch-Blöcken. Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 14/27 Abfangen von Exceptions ● Beispiel: public public void void doYourJob() doYourJob() {{ Scanner Scanner scanner scanner == new new Scanner(System.in); Scanner(System.in); System.out.print("a: "); System.out.print("a: "); int int aa == scanner.nextInt(); scanner.nextInt(); System.out.print("b: System.out.print("b: "); "); int int bb == scanner.nextInt(); scanner.nextInt(); }} try try {{ System.out.println("a/b System.out.println("a/b == "" ++ a/b); a/b); }} catch(ArithmeticException catch(ArithmeticException e) e) {{ System.out.println("Wir System.out.println("Wir haben haben da da ein ein Problem: Problem: "" ++ e.getMessage()); e.getMessage()); System.out.println( System.out.println( "Das "Das haetten haetten Sie Sie nicht nicht tun tun sollen..."); sollen..."); }} Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 15/27 Abfangen von Exceptions Konsole java Excep4 a: 15 b: 0 Wir haben da ein Problem: / by zero Das haetten Sie nicht tun sollen... ● Beachte: Das Programm terminiert nicht mehr automatisch, nachdem die Exception geworfen wurde! Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 16/27 Beispiel – Daten aus Datei lesen ● ● Die Lösung in Java benötigt 2 Klassen aus dem Paket java.io, nämlich FileReader und BufferedReader. Eine Instanz der Klasse FileReader repräsentiert eine zum Lesen geöffnete Datei. Mit Hilfe der folgenden Zeile wird ein Objekt f vom Typ FileReader erzeugt, das Daten aus der Datei vals.txt lesen kann: FileReader FileReader ff == new new FileReader("vals.txt"); FileReader("vals.txt"); ● Beachte: Mit einem FileReader-Objekt kann man eine Datei nur zeichenweise einlesen. Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 17/27 Beispiel – Daten aus Datei lesen ● Instanzen der Klasse BufferedReader erlauben, Dateien zeilenweise einzulesen. Die folgende Anweisung erzeugt ein solches Objekt unter Verwendung des zuvor erzeugten FileReader-Objekts: BufferedReader BufferedReader bb == new new BufferedReader(f); BufferedReader(f); ● Beide Anweisungen können zusammengefasst werden: BufferedReader BufferedReader bb == new new BufferedReader(new BufferedReader(new FileReader("vals.txt")); FileReader("vals.txt")); ● Damit sieht der 1. Lösungsversuch wie folgt aus: Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 18/27 Beispiel – Daten aus Datei lesen import import java.io.*; java.io.*; public public class class Mittelwert Mittelwert {{ private private static static int int anzahl anzahl == 0; 0; public public static static int int parse(String parse(String s) s) {{ anzahl++; anzahl++; return return Integer.parseInt(s); Integer.parseInt(s); }} Fortsetzung auf nächster Folie Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 19/27 Beispiel – Daten aus Datei lesen public public static static void void main(String[] main(String[] args) args) {{ Scanner Scanner scanner scanner == new new Scanner(System.in); Scanner(System.in); System.out.print("Dateiname: System.out.print("Dateiname: "); "); String String fileName fileName == scanner.next(); scanner.next(); BufferedReader BufferedReader datei datei == new new BufferedReader(new BufferedReader(new FileReader(fileName)); FileReader(fileName)); double double mittel mittel == 0.0; 0.0; String String line line == datei.readLine(); datei.readLine(); while while (( line line != != null null )) {{ mittel mittel += += parse(line); parse(line); line line == datei.readLine(); datei.readLine(); }} mittel mittel /= /= anzahl; anzahl; Fortsetzung auf nächster Folie System.out.println("Mittelwert: System.out.println("Mittelwert: "" ++ mittel); mittel); }} }} Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 20/27 Beispiel – Daten aus Datei lesen Aber: Der Versuch, die Klasse zu übersetzen (javac Mittelwert.java) liefert folgende Fehlermeldung: Mittelwert.java:16: Mittelwert.java:16:unreported unreportedexception exception java.io.FileNotFoundException; java.io.FileNotFoundException;must mustbe becaught caughtor or declared to be thrown declared to be thrown new newBufferedReader(new BufferedReader(newFileReader(fileName)); FileReader(fileName)); ^^ Mittelwert.java:18: Mittelwert.java:18:unreported unreportedexception exception java.io.IOException; must be caught java.io.IOException; must be caughtor ordeclared declaredto to be thrown be thrown String Stringline line==datei.readLine(); datei.readLine(); ^^ Mittelwert.java:21: Mittelwert.java:21:unreported unreportedexception exception java.io.IOException; must be caught java.io.IOException; must be caughtor ordeclared declaredto to be thrown be thrown line line==datei.readLine(); datei.readLine(); ^^ Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 21/27 Beispiel – Daten aus Datei lesen }} public public static static void void main(String[] main(String[] args) args) {{ Scanner Scanner scanner scanner == new new Scanner(System.in); Scanner(System.in); FileNotFoundException System.out.print("Dateiname: System.out.print("Dateiname: "); "); möglich String String fileName fileName == scanner.next(); scanner.next(); BufferedReader BufferedReader datei datei == new new BufferedReader(new BufferedReader(new FileReader(fileName)); FileReader(fileName)); double double mittel mittel == 0.0; 0.0; String String line line == datei.readLine(); datei.readLine(); IOException while while (( line line != != null null )) {{ möglich mittel += parse(line); mittel += parse(line); line line == datei.readLine(); datei.readLine(); }} mittel mittel /= /= anzahl; anzahl; System.out.println("Mittelwert: System.out.println("Mittelwert: "" ++ mittel); mittel); }} Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 22/27 Beispiel – Daten aus Datei lesen ● Mögliche Lösung: throws-Klausel im Kopf der main-Methode: import import java.io.*; java.io.*; import import java.util.Scanner; java.util.Scanner; public public class class Mittelwert2 Mittelwert2 {{ private private static static int int anzahl anzahl == 0; 0; public static int parse(String public static int parse(String s) s) {{ …… }} public public static static void void main(String[] main(String[] args) args) throws FileNotFoundException, throws FileNotFoundException, IOException IOException {{ ... ... }} }} ● Effekt: Reicht die Exception durch zur aufrufenden Methode, in diesem Fall das Java-Laufzeitsystem, das das Programm mit einer Fehlermeldung abbricht. Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 23/27 Beispiel – Daten aus Datei lesen Konsole java javaMittelwert2 Mittelwert2 Datei: Datei:bals.txt bals.txt Exception Exceptionin inthread thread"main" "main"java.io.FileNotFoundException: java.io.FileNotFoundException:bals.txt bals.txt (Das (DasSystem Systemkann kanndie dieangegebene angegebeneDatei Dateinicht nichtfinden) finden) at atjava.io.FileInputStream.open(Native java.io.FileInputStream.open(NativeMethod) Method) at atjava.io.FileInputStream.<init>(Unknown java.io.FileInputStream.<init>(UnknownSource) Source) at atjava.io.FileInputStream.<init>(Unknown java.io.FileInputStream.<init>(UnknownSource) Source) at atjava.io.FileReader.<init>(Unknown java.io.FileReader.<init>(UnknownSource) Source) at atMittelwert.main(Mittelwert2.java:16) Mittelwert.main(Mittelwert2.java:16) Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 24/27 Beispiel – Daten aus Datei lesen ● Alternative: Exceptions abfangen public public static static void void main(String[] main(String[] args) args) {{ BufferedReader BufferedReader datei datei == null; null; Scanner scanner = new Scanner(System.in); Scanner scanner = new Scanner(System.in); boolean boolean success; success; do do {{ System.out.println("Dateiname: System.out.println("Dateiname: "); "); String fileName = scanner.next("Dateiname: String fileName = scanner.next("Dateiname: "); "); System.out.println("Datei: " + fileName); System.out.println("Datei: " + fileName); try try {{ datei datei == new new BufferedReader(new BufferedReader(new FileReader(fileName)); FileReader(fileName)); success = true; success = true; }} catch catch (( FileNotFoundException FileNotFoundException ee )) {{ success success == false; false; }} }} while while (( !success !success ); ); Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 25/27 Beispiel – Daten aus Datei lesen double double mittel mittel == 0.0; 0.0; }} try try {{ String String line line == datei.readLine(); datei.readLine(); while ( line != while ( line != null null )) {{ mittel mittel += += parse(line); parse(line); line line == datei.readLine(); datei.readLine(); }} mittel mittel /= /= anzahl; anzahl; System.out.println("Mittelwert: System.out.println("Mittelwert: "" ++ mittel); mittel); }} catch catch (( IOException IOException ee )) {{ System.out.println("Fehler System.out.println("Fehler beim beim Einlesen"); Einlesen"); System.exit(0); System.exit(0); }} Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 26/27 Erzeugen von Exceptions ● Mit der throw-Anweisung können Exceptions auch selbst ausgelöst werden: Syntaxregel throw <Exception> ● Beispiel: if if (param (param <= <= 0){ 0){ Exception Exception newException newException == new new IllegalArgumentException( IllegalArgumentException( "Parameter muss größer Null sein" "Parameter muss größer Null sein"); ); throw newException; throw newException; }} Prof. Dr. Oliver Haase, HTWG Konstanz Karl Martin Kern, Seitenbau GmbH Achim Bitzer, Seitenbau GmbH 27/27