Technische Universität Darmstadt Telecooperation/RBG Grundlagen der Informatik I Thema 16: Ausnahmebehandlung Dr. Guido Rößling Copyrighted material; for TUD student use only Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Übersicht • Fehler und deren Klassifizierung • Fehlerbehandlung ohne eigenständige Sprachmechanismen und deren Probleme • Grundkonzepte der Fehlerbehandlung mit eigenständigen Sprachmechanismen am Beispiel von Java • Vorteile der Fehlerbehandlung mit eigenständigen Sprachmechanismen am Beispiel von Java • Zusammenfassung Grundlagen der Informatik I: T16 2 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Klassifikation von Fehlern • Lexikalische Fehler: Falsche oder unbekannte Worte ... int[] result = neu int[5]; result.size(); // ... // • Syntaxfehler: Falsche Anordnung von Worten //... move(); public static void main(String[] args) { // ... } //... Lexikalische und syntaktische Fehler werden vom Compiler entdeckt und signalisiert Grundlagen der Informatik I: T16 3 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Klassifikation von Fehlern • Laufzeitfehler: ein Ereignis, das während des Ablaufs eines Programms vorkommt und den normalen Kontrollfluss der Anweisungen stört à Fehlerterminierung – Division durch 0 – Ein Grafikobjekt soll gezeichnet werden, existiert aber nicht • Intentionsfehler: Programm läuft, aber mit unerwünschtem Ergebnis Grundlagen der Informatik I: T16 4 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Fehlerbehandlung • Umgang mit Fehlern ist ein wichtiger Teil der Softwareentwicklung: Qualitätszusicherung! • Die übliche Reaktion auf nicht abgefangene Ausnahmesituationen: Programmabsturz! – Das kann manchmal besser sein als fehlerhafte Ereignisse, die für eine lange Zeit unentdeckt bleiben. • Komplexe Programme/verteilte Anwendungen ohne jede Reaktion auf Ausnahmen sind nicht akzeptabel. • Telekommunikationssysteme • Steuerungssysteme, z.B. Raketen, Kernkraftwerke, ... • Programme, die tolerant (graceful) mit Fehlern umgehen, werden robust genannt. Grundlagen der Informatik I: T16 5 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Fehlerbehandlung, Bug, Debugging • Diese Vorlesung à Laufzeitfehler abfangen und beheben – Schwerwiegende versus leichtgewichtige Fehler • Foliensatz T19 à Intentionsfehler: Testen/verifizieren, dass die Software das tut, was sie tun sollte • Bug: Bezeichnung für alle Programmfehler – Ursprung: Im einem Computer löste ein totes Insekt (engl. Bug) in einem Relais einen Fehler aus – Meist schwer zu finden, „100% Bug-free“ – unmöglich • Debugging = Fehlersuche • Beide Worte gehen auf Grace Murray Hopper (à T12.28) zurück Grundlagen der Informatik I: T16 6 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Schwerwiegende Laufzeitfehler (Error) • Zwei Sorten von schwerwiegenden Laufzeitfehlern – Systemfehler: Fehler in der Java-VM, Speichermangel, … • Nicht „Schuld“ von Anwendungsprogrammierer • Können prinzipiell nicht abgefangen werden und führen direkt zum Programmabsturz – Programmierfehler, nach denen eine Programmfortsetzung nicht mehr möglich ist • Eine benötigte Klasse ist nicht vorhanden Grundlagen der Informatik I: T16 7 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Leichtgewichtige Fehler • Ausnahmen (Exceptions) können innerhalb des Programms abgefangen werden; Programmfortsetzung ist möglich. Problem: Eingabe eines fehlerhaften Dateinamens durch Benutzer Behebung: Neueingabe verlangen Problem: Fehlerhafte Daten in einer Datei, die ignoriert werden können, z.B. nicht interpretierbare Bild- oder Audiosignale Behebung: Ignorieren Problem: Zusammenbruch einer Netzverbindung Behebung: Neuaufbau der Verbindung Grundlagen der Informatik I: T16 8 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Einige typische Ausnahmen public void printPerson() { Person aPerson = null; // ... printName(aPerson); // ... } public void printName(Person p) { System.out.println(p.name); } • Problem: Sende eine Nachricht an "null" • Ergebnis: NullPointerException • Zugriff auf eine Methode oder Instanzvariable eines nichtexistierenden Objekts (null) • Die Existenz eines Objekts sollte vor dem Zugriff geprüft werden! Grundlagen der Informatik I: T16 9 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Einige typische Ausnahmen int[] matrikelNummern = new int[27]; for (int i = 0; i <= 27; i++) System.out.println(matrikelNummern[i]); • Problem: illegaler Array-Zugriff mit i == 27 • Ergebnis: ArrayIndexOutOfBoundsException • Gültig sind nur Positionen i mit 0 <= i < array.length • Besonders trickreich bei Aufrufparametern • Immer erst überprüfen, wie viele Argumente es gibt (args.length) Grundlagen der Informatik I: T16 10 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Einige typische Ausnahmen public static void main(String[] args) { int count; count = Integer.parseInt(args[1]); // ... } Dieser Zugriff führt potentiell zu mehreren Fehlern! Problem 1: illegaler Array-Zugriff, falls keine Parameter an das Programm übergeben wurden. In diesem Fall hat args keine Elemente – Zugriff auf args[1] schlägt fehl. à Ergebnis: ArrayIndexOutOfBoundsException Problem 2: Versuch eine Nicht-Zahl zu parsen, falls args[1] z.B. "Hello" ist. Text kann nicht in eine Zahl umgewandelt werden. à Ergebnis: NumberFormatException Grundlagen der Informatik I: T16 11 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Fehlerbehandlung • Zwei Arten von Fehlerbehandlung: – Ohne eigenständige Sprachmechanismen • In Sprachen wie C oder Pascal – Mit eigenständigen Sprachmechanismen • In Sprachen wie etwa Ada, Smalltalk, Java • Im Folgenden werden wir – Die Probleme der Sprachen ohne dedizierte Fehlerbehandlungsmechanismen diskutieren – Fehlerbehandlung mit dedizierten Sprachmechanismen und deren Vorteile am Beispiel von Java vorstellen Grundlagen der Informatik I: T16 12 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Übersicht • Fehler und deren Klassifizierung • Fehlerbehandlung ohne eigenständige Sprachmechanismen und deren Probleme • Grundkonzepte der Fehlerbehandlung mit eigenständigen Sprachmechanismen am Beispiel von Java • Vorteile der Fehlerbehandlung mit eigenständigen Sprachmechanismen am Beispiel von Java • Zusammenfassung Grundlagen der Informatik I: T16 13 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Fehlerbehandlung ohne Sprachmechanismen • Zwei Möglichkeiten von Fehlersignalisierung – Programmabbruch (!) - Prozeduren/ Funktionen einer Sprache, melden keine Fehler • Zugriffsversuch auf eine nicht vorhandene Datei endete in „alten“ Versionen von Pascal mit einem Programmabsturz. – Fehler werden signalisiert • Meist über unübliche Rückgabewerte von Methoden • z.B. –1 statt positiver Zahl • Abfangen und Behandlung von Fehlern – Fehlerbehandlung wird (vom Programmierer) ignoriert – Fehler werden behandelt, z.B. über Fallunterscheidungen Grundlagen der Informatik I: T16 14 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Fehlerbehandlung ohne Sprachmechanismen • Wir betrachten den Fall: – Unübliche Rückgabewerte zur Signalisierung – Bedingungslogik zur Behandlung • Problem: Keine Trennung der normalen Verarbeitung von der Fehlerbehandlung • Betrachten wir eine Methode (in Pseudocode), die eine ganze Datei von der Festplatte in den Hauptspeicher liest. readFile { open the file; determine its size; allocate that much memory; read the file into memory; close the file; } Grundlagen der Informatik I: T16 15 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Fehlerbehandlung ohne Sprachmechanismen • Auf dem ersten Blick wirkt die Methode sehr simpel • Aber sie ignoriert alle möglichen Fehler: – Die Datei kann nicht geöffnet werden. – Die Länge der Datei kann nicht festgestellt werden. – Es ist nicht genug Platz im Hauptspeicher vorhanden. – Lesen von der Datei schlägt fehl. – Die Datei kann nicht geschlossen werden. • Um diese Fälle zu behandeln, müssen wir eine Menge Code hinzufügen, wie die folgende Implementierung zeigt. Grundlagen der Informatik I: T16 16 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Fehlerbehandlung ohne Sprachmechanismen errorCodeType readFile { initialize errorCode = 0; open the file; if (theFileIsOpen) { determine its size; if (gotTheFileLength) { allocate that much memory; if (gotEnoughMemory) { read the file into memory; if (readFailed) { errorCode = -1; } } else { errorCode = -2; } } else { errorCode = -3; } close the file; if (theFileDidntClose && errorCode == 0) { errorCode = -4; } else { errorCode = errorCode && -4; } } else { errorCode = -5; } return errorCode; } Grundlagen der Informatik I: T16 17 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Fehlerbehandlung ohne Sprachmechanismen • Mit eingebauter Fehlerbehandlung bekommen wir 29 anstelle von 7 Zeilen Code - ein Faktor von fast 400%! • Der Ursprungscode geht in dem Code für Entdeckung, Signalisierung und Behandlung von Fehlern verloren. • Der logische Fluss des Codes ist verloren gegangen, was die Beurteilung, ob der Code das Richtige macht, sehr erschwert. – Wird die Datei tatsächlich in dem Fall geschlossen, dass es nicht genügend Speicherplatz gibt? • Noch schwieriger wird es, wenn die Methode später modifiziert wird! Grundlagen der Informatik I: T16 18 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Fehlerbehandlung ohne Sprachmechanismen • Schlussfolgerung: Konflikt zwischen Zuverlässigkeit und Übersichtlichkeit – Werden Fehler behandelt, so entstehen unübersichtliche Programmstrukturen (z.B. viele Fallunterscheidungen) – Werden Fehler ignoriert, so ist die Zuverlässigkeit des Programms nicht sichergestellt Eine Ausnahmebehandlung ohne eigenständige Sprachkonstrukte hat sich nicht bewährt! Grundlagen der Informatik I: T16 19 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Übersicht • Fehler und deren Klassifizierung • Fehlerbehandlung ohne eigenständige Sprachmechanismen und deren Probleme • Grundkonzepte der Fehlerbehandlung mit eigenständigen Sprachmechanismen am Beispiel von Java • Vorteile der Fehlerbehandlung mit eigenständigen Sprachmechanismen am Beispiel von Java • Zusammenfassung Grundlagen der Informatik I: T16 20 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Ausnahmebehandlung in Java • In Java werden Ausnahmen als Objekte dargestellt. • Der Java-Compiler erzwingt die Behandlung von bestimmten Typen von Fehlern. • Wenn ein Fehler während der Ausführung einer Methode auftritt: – Die Methode [oder das Laufzeitsystem] erzeugt und wirft ein AusnahmeObjekt, das Informationen über den Fehlertyp und Status des Programms, als der Fehler passierte, usw. enthält – Die Ausnahme wird ausgelöst: die Kontrolle und das erzeugte AusnahmeObjekt wird dem Laufzeitsystem übergeben. – Das Laufzeitsystem sucht Code für die Behandlung der Ausnahme. • Kandidaten dafür sind Methoden in der Aufrufkette der Methode, in der der Fehler auftrat. • Die Aufrufkette wird rückwärts durchsucht. Grundlagen der Informatik I: T16 21 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Auslösen von Ausnahmen public class Car { public void start() { // . . . // battery might be empty // driver might not be authorized } } Die Batterien sind möglicherweise (fast) leer. Um einen Programmabsturz zu vermeiden, soll eine Ausnahme ausgelöst werden à BatteryLowException Möglicherweise liegt keine Berechtigung vor, das Auto zu fahren à Ausnahme: SecurityException Grundlagen der Informatik I: T16 22 Auslösen von Ausnahmen public class Car { public void start() { Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Dieser Code wird vom Übersetzer so nicht akzeptiert! if (batteryLevel <= 5) throw new BatteryLowException( "Battery is empty"); if (!driver.isAuthorized()) throw new SecurityException( "No access rights"); // start the car } } throw-Anweisung: throw Exception-Object. Nebenbedingung: Exception-Object muss vom Typ Exception abgeleitet sein (mehr gleich). Fast immer direkt durch new erzeugt. Grundlagen der Informatik I: T16 23 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Deklaration eventuell ausgelöster Ausnahmen public class Car { public void start() throws BatteryLowException, SecurityException { // . . . // start car } } Die Methode muss in der Signatur deklarieren, dass sie potentiell Ausnahmen wirft! Potentiell ausgelöste Ausnahmen gehören zu der Signatur einer Methode genau so wie der Rückgabetyp. Syntax der Deklaration: throws <Exception-List>. <Exception-List> = <Exception-Name> {"," <Exception-List>}. • Es können mehrere Ausnahmetypen deklariert werden • Java Compiler überprüft, ob die Deklaration korrekt ist – Können undeklarierte, unbehandelte Ausnahmen auftreten? Grundlagen der Informatik I: T16 24 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Aufruf von Methoden, die Ausnahmen auslösen public class Bar { // ... public void doSmthWithCar(Car car) { // ... car.start(); // ... } } Dieser Code wird vom Übersetzer nicht akzeptiert! Grund: doSmthWithCar ruft eine Methode auf, welche Ausnahmen auslösen könnte. Diese werden aber ignoriert à Programmabsturz! Grundlagen der Informatik I: T16 25 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Aufruf von Methoden, die Ausnahmen auslösen public class Bar { public void doSmthWithCar(Car car) { // ... try-Block signalisiert die Bereitschaft, try { auftretende Ausnahmen abzufangen car.start(); und zu behandeln } catch (BatteryLowException ble) { // Exception handling Das Abfangen und die } Behandlung von catch (SecurityException se) { Ausnahmen erfolgt in // Exception handling catch-Blocks. } // ... } } 1. Möglichkeit: Die aufrufende Methode behandelt die von aufgerufenen Methoden erzeugten Ausnahmen Grundlagen der Informatik I: T16 26 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Behandlung auftretender Ausnahmen • Jeder catch-Block deklariert einen formalen Parameter – Beispiel: catch(SecurityException se) • Der Parametertyp legt den Ausnahmetyp fest, welchen der catch-Block abfängt und behandelt – Hier: SecurityException • Der Parameter (hier: se) ist lokale Variable im catch-Block – Erlaubt Verweise auf das zu behandelte Ausnahme-Objekt – Erlaubt Zugriff auf Methoden oder Attribute der Ausnahme • Ausnahmen sind im Prinzip ganz normale Java Objekte, definiert in ganz normalen Java Klassen! • Typische Methodenaufrufe: – se.getMessage() – Zugriff auf Fehlermeldungstext – se.printStackTrace() – Aufrufreihenfolge ausgeben Grundlagen der Informatik I: T16 27 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Behandlung mehrerer Ausnahmen eines Blocks Wie behandelt man mehrere mögliche Ausnahmen eines Befehls oder Befehlsblocks? • Es können mehrere catch-Blöcke zu einem try-Block angegeben werden! – Einzelne Befehle, die möglicherweise mehrere Ausnahmen auslösen können, werden auch in einem try-Block eingeschlossen. • Es wird der erste passende catch-Block ausgeführt – Vorsicht, wenn Ausnahmen in einer Vererbungsbeziehung stehen (mehr gleich)! Grundlagen der Informatik I: T16 28 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Weiterreichen auftretender Ausnahmen public class Bar { public void doSmthWithCar(Car car) throws BatteryLowException, SecurityException { // ... car.start(); // ... } } 2. Möglichkeit: Die aufrufende Methode reicht alle oder einige der Ausnahmen entlang der Aufrufkette weiter. Grundlagen der Informatik I: T16 29 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Weiterreichen auftretender Ausnahmen public class Client { public static void main(String[] args) { // ... Car car = ...; Bar o2 = new Bar(); o2.doSmthWithCar(car); // ... } } :Client main o2: Bar :Car o2.doSmthWithCar() start() Suche die erste Methode, die einen catch-Block für die ausgelöste Ausnahme hat, und fahre mit dem Code im catch-Block fort. Wird kein passender catch-Block gefunden, endet das Programm mit einer Fehlermeldung. Grundlagen der Informatik I: T16 30 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Sicherstellung der Ausführung von Aktionen Wie kann sichergestellt werden, dass in jedem Fall bestimmte Aktionen ausgeführt wurden? • Problem: Bei Programmen mit Ausnahmebehandlung gibt es mehrere Möglichkeiten, das Programm zu verlassen. – Manchmal müssen bestimmte Aktionen garantiert werden, egal, ob nun eine Ausnahme aufgetreten ist oder nicht. • Beispiel: Schreiben in eine erfolgreich geöffnete Datei – Die Datei sollte in jedem Fall geschlossen werden – egal, ob Daten schreibbar waren oder nicht Grundlagen der Informatik I: T16 31 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Der finally-Block Code-Duplikation public void test() { Switch sw = new Switch(); try { sw.on(); // code der evtl. Exceptions wirft sw.off(); } catch (BatteryLowException e) { sw.off(); // unnoetige Code-Duplikation System.err.println("Caught BatteryLowException"); } catch (SecurityException e) { sw.off(); // unnoetige Code-Duplikation System.err.println("Caught SecurityException"); } } Grundlagen der Informatik I: T16 32 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Sicherstellung der Ausführung von Aktionen • Dazu bietet Java den finally-Block • Befehle des finally-Blocks werden immer ausgeführt: – Nach Ende des try-Blocks, falls keine Ausnahme auftrat – Nach Ende eines catch-Blocks, falls eine Ausnahme auftrat public void test() { Switch sw = new Switch(); try { } sw.on(); // code that may throw exceptions } catch (BatteryLowException blExc) { // ... } catch (SecurityException secEx) { // ... } finally { sw wird auf jeden Fall sw.off(); abgeschaltet, unabhängig vom } Kontrollfluss des Programms Grundlagen der Informatik I: T16 33 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Vorteile des finally-Blocks • Die Anweisungen des finally-Blocks werden unabhängig vom Auftreten einer Ausnahme ausgeführt – Keine Duplizierung von Code, der in jedem Fall – ob mit oder ohne Exception – auszuführen ist • Achtung: – Befehle im finally-Block können wiederum Ausnahmen auslösen! • Schließen von Dateien oder Netzwerkverbindungen, Null Pointer, ... – Behandlung im finally-Block wie in jedem anderen Block... Grundlagen der Informatik I: T16 34 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Übersicht • Fehler und deren Klassifizierung • Fehlerbehandlung ohne eigenständige Sprachmechanismen und deren Probleme • Grundkonzepte der Fehlerbehandlung mit eigenständigen Sprachmechanismen am Beispiel von Java • Vorteile der Fehlerbehandlung mit eigenständigen Sprachmechanismen am Beispiel von Java • Zusammenfassung Grundlagen der Informatik I: T16 35 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Vorteile der Fehlerbehandlung mit eigenständigen Sprachmechanismen 1. Trennung der normalen Verarbeitung von der Fehlerbehandlung 2. Weitergabe von Fehlern entlang der dynamischen Aufrufkette 3. Unterscheidung und Gruppierung verschiedener Fehlertypen 4. Kontrolle durch den Compiler, dass bestimmte Fehlertypen auf jeden Fall behandelt werden Grundlagen der Informatik I: T16 36 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © 1. Trennung der Fehlerbehandlung • Javas Konstrukte für Ausnahmebehandlung ermöglichen die Trennung des normalen Programmcodes von Fehlerbehandlung • Achtung! Ausnahmebehandlung erspart keine Arbeit – Der Vorteil liegt in der Trennung. void readFile() { try { open the file; determine its size; allocate that much memory; read the file into memory; close the file; } catch (fileOpenFailed) { doSomething; } catch (sizeDeterminationFailed) { doSomething; } catch (memoryAllocationFailed) { doSomething; } catch (readFailed) { doSomething; } catch (fileCloseFailed) { doSomething; } } Grundlagen der Informatik I: T16 37 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © 2. Fortpflanzung der Ausnahmen • Angenommen, readFile ist die vierte Methode in einer Kette von Methodenaufrufen: method1, method2, method3, readFile – Dabei ist method1 die einzige Methode, die daran interessiert ist, die Fehler von readFile zu behandeln. • In traditionellen Sprachen müssen method2 und method3 die Fehlerkodierungen weiterleiten, die von readFile zurückgegeben werden, bis sie method1 erreichen. method1 { call method2; } method2 { call method3; } method3 { call readFile; } Grundlagen der Informatik I: T16 38 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © 2. Fortpflanzung der Ausnahmen method1 { errorCodeType error; error = call method2; if (error) doErrorProcessing; else proceed; } errorCodeType method3 { errorCodeType error; error = call readFile; if (error) return error; else proceed; } errorCodeType method2 { errorCodeType error; error = call method3; if (error) return error; else proceed; } Grundlagen der Informatik I: T16 39 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © 2. Fortpflanzung der Ausnahmen • Im Gegensatz dazu sucht das Laufzeitsystem von Java rückwärts in der Aufrufkette nach Methoden, die an der Behandlung der Fehler interessiert sind. method1 { try { call method2; } catch (exception) { doErrorProcessing; } } method2 throws exception { call method3; } method3 throws exception { call readFile; } Grundlagen der Informatik I: T16 40 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © 3. Hierarchie der Java Ausnahmetypen • Alle Ausnahmetypen in Java erben von der vordefinierten Klasse java.lang.Throwable “Schwerwiegende" VM Ausfälle sollen und können nicht von einem Programm abgefangen werden können ignoriert werden können vom Programmierer erweitert werden Grundlagen der Informatik I: T16 41 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Die Klasse Throwable Throwable Erzeugt ein Throwable-Objekt mit einer spezifischen Fehlermeldung (error-message) Throwable() Throwable(String) getMessage() printStackTrace() printStackTrace(PrintStream) ... Gibt Fehlermeldung zurück Gibt die Aufrufkette beim Auslösen der Ausnahme aus Grundlagen der Informatik I: T16 42 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Methoden der Klasse Exception public class ExceptionMethods { public static void main(String[] args) { try { throw new Exception("Hier kommt eine Exception"); } catch (Exception e) { System.out.println("Exception gefangen"); System.out.println("e.getMessage(): "+e.getMessage()); System.out.println("e.toString(): "+e.toString()); System.out.println("e.printStackTrace():"); e.printStackTrace(); } } } Grundlagen der Informatik I: T16 43 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Schwerwiegende Fehler: Error • Programm kann nicht • Es macht keinen Sinn, fortgeführt werden, z.B. kein solche Fehler abzufangen Speicher mehr vorhanden und zu behandeln: Der Compiler erzwingt die Behandlung von diesen Fehlern nicht. • Führen zum Programmabsturz Grundlagen der Informatik I: T16 44 Ungeprüfte Ausnahmetypen: RuntimeException Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © • RuntimeExceptions sind Fehler, die überall im Programm auftreten könnten, abhängig von Laufzeitbedingungen: – Aufrufen einer Methode auf einem null-Objekt, der Versuch außerhalb der Grenzen eines Array zu lesen / schreiben, usw. Diese Fehler können, müssen aber nicht abgefangen werden. Grundlagen der Informatik I: T16 45 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Ungeprüfte Ausnahmetypen: RuntimeException • Das Erzwingen der Behandlung dieser Fehler würde das Programm unnötig unübersichtlich machen – Solche Fehler können potentiell überall auftreten … • Ein catch-Block für NullPointerException wäre für jeden Operationsaufruf notwendig – Auch wenn der Programmierer sicher ist, dass eine Variable an einer bestimmten Stelle des Programms ein gültiges Objekt enthält – Der Compiler kann das statisch nicht testen public static void main(String[] args) { // evtl. ArrayIndexOutOfBoundsExc., NumberFormatException Double doubleValue = Double.parseDouble(args[0]); // evtl. ArrayIndexOutOfBoundsExc., NumberFormatException Integer intValue = Integer.parseInt(args[1]) } Grundlagen der Informatik I: T16 46 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Geprüfte Ausnahmetypen • Geprüfte Ausnahmetypen sind alle Ausnahmetypen, die von Exception aber nicht von RuntimeException erben • Mehrere vordefinierte Ausnahmeklassen: FileNotFoundException,IOException, etc. Anwendungsspezifische Ausnahmen können vom Programmierer als direkte oder indirekte Erben von Exception definiert werden. Grundlagen der Informatik I: T16 47 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Geprüfte Ausnahmetypen • Der Compiler erzwingt die Behandlung von geprüften Ausnahmetypen • Eine Methode muss für geprüfte Ausnahmen – entweder eine Behandlung definieren (catch), oder – alle Ausnahmen dieser Typen, die innerhalb des Methodenbereiches vorkommen, weitergeben, indem sie in einem throws-Ausdruck deklariert werden. Der Bereich einer Methode M ist nicht nur der eigene Code, sondern auch der Code von Methoden, die von M aufgerufen werden. Diese Definition ist rekursiv. Grundlagen der Informatik I: T16 48 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Gruppierung von Ausnahmetypen • Exceptions sind normale Java-Objekte mit Vererbungshierarchie • Daher kann man Spezialisierungen / Verallgemeinerungen definieren zwischen den Exception-Typen • Eine IndexOutOfBoundsException wird geworfen, wenn ein Index außerhalb des gültigen Bereiches liegt – ArrayIndexOutOfBoundsException ist eine Unterklasse für Array-Zugriffe – “Außerhalb des Bereichs”: Indexwert ist negativ oder größer oder gleich der Array-Länge • Der Programmierer einer Methode kann mehr oder weniger spezifische Exceptions behandeln Grundlagen der Informatik I: T16 49 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Gruppierung von Ausnahmetypen Die Fassung von op1 behandelt public void op1() { verschiedene Exceptions verschieden. // ... catch (ArrayIndexOutOfBoundsException invInd) { // macht etwas mit invInd } catch (NullPointerException npe) { // macht etwas mit npe } catch (NoSuchElementException eType) { // macht etwas mit eType } } public void op1() { } // ... catch (RuntimeException e) { // macht etwas mit e } Hier werden alle Exceptions gleich behandelt. Grundlagen der Informatik I: T16 50 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Gruppierung von Ausnahmetypen public void op1() { // ... catch (RuntimeException e) { // macht etwas mit e } } Man könnte auch mit Fallunterscheidungen die verschiedenen Subtypen von RuntimeException unterscheiden. Die Fassung der vorherigen Folie ist: • besser dokumentiert • einfacher zu warten public void op1() { } // ... catch (Exception e) { // macht etwas mit e } Man kann sogar alle Exceptions gleich behandeln. NICHT EMPFOHLEN! Grundlagen der Informatik I: T16 51 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Gruppierung von Ausnahmetypen public void op1() { // ... catch (ArrayIndexOutOfBoundsException invInd) { // macht etwas mit invInd } catch (RuntimeException e) {Laufzeitsystem wählt den ersten // macht etwas mit e catch-Block, der den Typ der } } ausgelösten Ausnahme oder einen Supertyp davon behandelt. public void op1() { // ... catch (RuntimeException e) { // macht etwas mit e } catch (ArrayIndexOutOfBoundsException invInd) { // macht etwas mit invInd } } Was passiert bei der Auslösung einer ArrayIndexOutOfBoundsException? Grundlagen der Informatik I: T16 52 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © „Vererbung“ von Ausnahmen public public public public class class class class CarException extends Exception {} NoGasoline extends CarException {} NoSpecialGasoline extends NoGasoline {} BadWeather extends Exception {} public class Car { public void start() throws NoGasoline { … } public void stop() throws CarException { … } } public class SportsCar extends Car { public void start() throws NoSpecialGasoline { … } public void stop() throws BadWeather { … } } public static void main(String[] args) { try { new SportsCar().start(); } catch (NoSpecialGasoline e) { } } Dieser Code wird vom Übersetzer so nicht akzeptiert! Grundlagen der Informatik I: T16 53 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © „Vererbung“ von Ausnahmen • Gegeben sei eine Methode f, die Exceptions auslösen kann und in einem Erben überschrieben wird. • Regel 1: Der Erbe darf neben den im Vorfahr deklarierten Exceptions auch konkretere Untertypen davon werfen. • Regel 2: Der Erbe darf keine zusätzlichen Exceptions deklarieren, die nicht zu denen des Vorfahren passen. – Es dürfen keine „neuen“ Exceptiontypen hinzugefügt werden. – Konkretere Typen hingegen sind erlaubt (siehe Regel 1). • Grund: Vererbungsregel 5 (à Substituierbarkeit T13.7) und – Keine „Überraschung“ durch nicht erwartbare Exceptions bei Verwendung der Basisklasse als statischen Typ! Grundlagen der Informatik I: T16 54 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Konstruktoren und Ausnahmen • Vor Aufruf des Konstruktors der Basisklasse darf nichts stehen, nicht einmal ein try Block. • Ausnahmen des Basisklassen-Konstruktors müssen im Konstruktor der abgeleiteten Klasse wieder aufgelistet werden. public class Car { public Car() throws NoGasoline {} } public class SportsCar extends Car { public SportsCar throws NoGasoline { super(); //wirft vielleicht eine NoGasoline Ausnahme //... } } NoGasoline kann nicht mit NoSpecialGasoline ersetzt werden Grundlagen der Informatik I: T16 55 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Bedeutung von Namen • Der Name einer Ausnahme ist typischerweise das wichtigste. • In der Regel wählt man lange, aussagekräftige Namen. • Der Code der Ausnahmeklasse selbst ist meistens minimal. • Nachdem man eine Ausnahme gefangen hat, benötigt man sie in der Regel nicht mehr. Grundlagen der Informatik I: T16 56 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Weiterleiten von Exceptions catch (Exception e) { System.out.println("An exception was thrown: "+e); throw e; // throw e.fillInStackTrace(); } • So viel wie möglich direkt erledigen und dann eine globalen Stelle den Rest erledigen lassen • fillInStackTrace speichert im Throwable Objekt Informationen über den aktuellen Zustand des AufrufStacks ab. Grundlagen der Informatik I: T16 57 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Prüfen auf erwartete Ausnahmen in JUnit 4 • Erinnern Sie sich an den Taschenrechner mit JUnit in T12? – Dort gab es eine Testmethode „divideByZero()“ – Diese wirft bei Aufruf eine ArithmeticException • Wir wollen testen, ob diese erwartete Exception auftritt – Wenn ja, ist das korrekt (erwartete Exception eingetreten) – Wenn nein, ist das ein Fehler im Sinne des Testens • Wie können wir die Exception über JUnit „abfangen“? • Wir nutzen einen Parameter für die @Test-Annotation – @Test(expected=ExceptionType.class) • Im Beispiel also: @Test(expected = ArithmeticException.class) public void divideByZero() { calculator.divide(0); } Grundlagen der Informatik I: T16 58 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Übersicht • Fehler und deren Klassifizierung • Fehlerbehandlung ohne eigenständige Sprachmechanismen und deren Probleme • Grundkonzepte der Fehlerbehandlung mit eigenständigen Sprachmechanismen am Beispiel von Java • Vorteile der Fehlerbehandlung mit eigenständigen Sprachmechanismen am Beispiel von Java • Zusammenfassung Grundlagen der Informatik I: T16 59 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Zusammenfassung • • Jedes Programm kann prinzipiell Fehler enthalten Java unterstützt die Fehlerbehandlung – Errors sind schwerwiegende Fehler à nicht behebbar – Ausnahmen sind Fehler, die behoben werden können • Im wesentlichen drei Vorgehensweisen: – Deklarieren und Weiterreichen der Ausnahme erfolgt durch „throws“ und Ausnahmetyp im Methodenkopf – Behandeln der Ausnahme(n) in try…catch der Methode – Laufzeit-Ausnahmen können ignoriert, dürfen aber natürlich auch behandelt werden! Grundlagen der Informatik I: T16 60 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Zusammenfassung • Die Exception-Behandlung erfolgt in try...catch – Ausnahmen auslösende Befehle (meist Methodenaufrufe) stehen in einem try-Block – Mögliche Ausnahmen werden in catch-Blöcken behandelt – Jeder catch-Block behandelt einen Ausnahmetyp – Dazu wird ein Parameter vom Ausnahmetyp deklariert • Die Suche nach dem „passenden“ catch erfolgt von oben nach unten – Der erste „passende“ catch-Block wird genutzt – Bei der Anordnung ist die Vererbungshierarchie beachten! • Befehle im finally-Block werden stets ausgeführt – Egal, ob eine Ausnahme auftrat oder nicht – Ideal, um „sauberzumachen“, etwa Dateien zu schließen Grundlagen der Informatik I: T16 61 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Zusammenfassung: Kontrollfluss im Fehlerfall Wie sieht der Kontrollfluss im Fehlerfall aus? 1. Erzeugung eines „passenden“ Ausnahme-Objekts • • Das Ausnahme-Objekt beschreibt Problem und ggf. Ursache • Aktuelle Klasse (Name!), evtl. Codezeile, Fehlerbeschreibung (Text) Die Anlegung des Ausnahme-Objekts kann erfolgen... • „automatisch“ durch das Laufzeitsystem (z.B. NullPointerException) • durch Methodenaufrufe ausgelöst (z.B. FileNotFoundException) • durch den Programmierer mittels „throw new XXX()“ 2. Die Laufzeitumgebung sucht nach passendem catch • • • Zunächst im aktuellen Block bis hin zur aktuellen Methode Dann in der Methode, die diese Methode aufrief… ...und so weiter in der Aufrufkette, ggf. bis zum Start des Programms Grundlagen der Informatik I: T16 62 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Ausnahme des Typs TE wird in einem try-Block ausgelöst Verlassen des try-Blocks Durchsuchen der catch-Klauseln catch-Klausel mit (Ober-)klasse TE gefunden? Ablauf: Ausnahmebehandlung nein ja Ausführung der Anweisungen des ersten solchen catch-Blocks Ausführung der Anweisungen des (optionalen) finally-Blocks Ausführung der Anweisungen des (optionalen) finally-Blocks catch-Block durchlaufen, ohne neue Ausnahme auszulösen? nein ja Fortsetzung hinter tryBlock Grundlagen der Informatik I: T16 Weitergabe des neuen Ausnahmeobjekts an den umliegenden try-Blocks 63