Ausnahmebehandlung mit try/catch

Werbung
Schon mal einen Blue
Screen gesehen?
Ausnahmebehandlung
OOPM, Ralf Lämmel
Beispiele für Ausnahmesituationen
Programmfehler
“precondition failed”
Unzulässige Nutzereingabe
“bad url”
Nichtverfügbarkeit von Ressourcen
“connection lost”
Verausgabung von Ressourcen
“stack overflow”
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
927
Verhalten eines Programmes
bei unzulässigen Eingaben
$ java Program 3 4
3+4=7
$ java Program 3
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at Program.main(Program.java:12)
$ java Program 3 vier
Exception in thread "main" java.lang.NumberFormatException: For input string: "vier"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:447)
at java.lang.Integer.parseInt(Integer.java:497)
at Program.main(Program.java:12)
Können wir uns bessere
Fehlermeldungen vorstellen?
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
928
Verhalten des Programmes
mit Ausnahmebehandlung
$ java Program 3 4
3+4=7
$ java Program 3
Incorrect number of arguments
$ java Program 3 vier
Argument(s) not a number
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
929
Quellen für Ausnahmesituationen im Programm
Haben Sie noch eine weitere Idee
für eine Ausnahmesituation?
public class Program {
public static void main(String[] args) {
Feldzugriff kann scheitern
int value1 = Integer.parseInt(args[0]);
int value2 = Integer.parseInt(args[1]);
int sum = value1 + value2;
Konvertierung in Zahl
kann scheitern
System.out.println(value1 + " + " + value2 + " = " + sum);
}
}
Illustrationen für Ausnahmebehandlung
siehe Repository: idioms.errorhandling
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
930
Ansatz der Ausnahmebehandlung
public class Program {
public static void main(String[] args) {
Teste dass args.length == 2
int value1 = Integer.parseInt(args[0]);
int value2 = Integer.parseInt(args[1]);
int sum = value1 + value2;
Behandle nichterfolgreiche
Konvertierung
System.out.println(value1 + " + " + value2 + " = " + sum);
}
}
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
931
Allgemeine Fragestellungen
1. Was ist ein Fehler bzw. eine Ausnahme?
2. Wie wissen wir, dass ein Fehler bzw. eine Ausnahme auftritt?
3. Wie weiß ein Programm dies?
4. Wie reagiert ein Programm auf einen Fehler bzw. eine Ausnahme?
5. Kann das Programm sich erholen?
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
932
Fehler
Der Begriff ist
hochgradig überladen.
Definition: ein unerlaubter Programmzustand
Beispiel: das Beispielprogramm darf nicht in
dem Zustand sein, dass es in die main-Funktion
eintritt wobei nur 1 Eingabewert ansteht.
Naives Modell der Fehlervermeidung: Die
Spezifikation von Methoden, Klassen und
Programmen definiert was erlaubte
Programmzustände sind. Jede Verwendung der
Methoden, Klassen und Programmen wird im
Voraus auf die Einhaltung der Spezifikation
überprüft.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
933
Ziele der Fehlerbehandlung
Vermeidung von inkonsistentem Verhalten
Rückkehr zu früherem, sicherem Programmpunkt
Kontrollierte Beendung des Programmes
Sicherung von Ergebnissen
Ausgabe von hilfreichen Fehlermeldungen
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
934
Techniken zur Fehlerbehandlung
Keine Behandlung
Terminierung des Programmes
Verwendung eines globalen Fehlerflags
Verwendung eines speziellen Rückgabewertes
Vereinbarung einer speziellen Funktion
Verwendung von Transaktionsmechanismen
Ausnahmebehandlung mit try/catch
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
935
Techniken zur Fehlerbehandlung
Keine Behandlung
Terminierung des Programmes
Verwendung eines globalen Fehlerflags
Verwendung eines speziellen Rückgabewertes
Vereinbarung einer speziellen Funktion
Verwendung von Transaktionsmechanismen
Ausnahmebehandlung mit try/catch
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
936
Verwendung eines globalen Fehlerflag
Wir “erfinden” java.lang.Integer.error.
Wir ignorieren das Problem der Feldgröße im folgenden.
int value1 = Integer.parseInt(args[0]);
boolean error = Integer.error;
Abfrage des
Fehlerflags nach
jedem Aufruf
int value2 = Integer.parseInt(args[1]);
error |= Integer.error;
if (!error) {
int sum = value1 + value2;
System.out.println(value1 + " + " + value2 + " = " + sum);
}
else {
System.err.println("Argument(s) not a number");
System.exit(-1);
}
Das Abfragen des Flags kann leicht
vergessen werden.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
937
Techniken zur Fehlerbehandlung
Keine Behandlung
Terminierung des Programmes
Verwendung eines globalen Fehlerflags
Verwendung eines speziellen Rückgabewertes
Vereinbarung einer speziellen Funktion
Verwendung von Transaktionsmechanismen
Ausnahmebehandlung mit try/catch
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
938
Verwendung eines speziellen Rückgabewertes
Wir ändern den Ergebnistyp von parseInt von int nach Integer.
(Integer ist ein Referenztyp für int.)
Wir interpretieren null als Fehler.
Integer value1 = Integer.parseInt(args[0]);
boolean error = value1 == null;
Integer value2 = Integer.parseInt(args[1]);
error |= value2 == null;
Interpretiere
null als Fehler
if (!error) {
int sum = value1 + value2;
System.out.println(value1 + " + " + value2 + " = " + sum);
}
else {
System.err.println("Argument(s) not a number");
System.exit(-1);
}
Fehler können weiterhin übersehen werden oder der
Fehlerwert kann fehlinterpretiert werden. Auch verlangt
diese Technik häufig Typänderungen.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
939
Techniken zur Fehlerbehandlung
Keine Behandlung
Terminierung des Programmes
Verwendung eines globalen Fehlerflags
Verwendung eines speziellen Rückgabewertes
Vereinbarung einer speziellen Funktion
Verwendung von Transaktionsmechanismen
Ausnahmebehandlung mit try/catch
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
940
Vereinbarung einer speziellen Funktion
Illustration für Cobol; Vereinbarung eines
Fehlerparagraphen für bestimmte Dateifehler.
DECLARATIVES.
HANDLE-FILE-ERRORS SECTION.
USE AFTER ERROR ON ACCOUNT-FILE.
HANDLE-ACOUNT-ERROR.
MOVE “ACOUNT”
TO PANIC-RESOURCE.
MOVE “FILE ERROR” TO PANIC-HEADER.
MOVE FILE-STATUS TO PANIC-CODE.
GO TO PANIC-STOP.
END-DECLARATIVES.
Diese Technik verlangt Sprachunterstützung.
Ausnahmen (siehe nachfolgend) sind allgemeiner.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
941
Techniken zur Fehlerbehandlung
Keine Behandlung
Terminierung des Programmes
Verwendung eines globalen Fehlerflags
Verwendung eines speziellen Rückgabewertes
Vereinbarung einer speziellen Funktion
Verwendung von Transaktionsmechanismen
Ausnahmebehandlung mit try/catch
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
942
Ausnahmebehandlung mit try/catch
try {
int value1 = Integer.parseInt(args[0]);
int value2 = Integer.parseInt(args[1]);
int sum = value1 + value2;
System.out.println(value1 + " + " + value2 + " = " + sum);
}
catch (NumberFormatException e) {
System.err.println("Argument(s) not a number");
System.exit(-1);
}
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
943
Der OO-Ansatz: Ausnahmen
Ausnahme: ein Ereignis während der
Ausführung des Programms welches zur
Unterbrechung des regulären Ablaufs führt.
Java-Repräsentation einer Ausnahme:
Objekte der Klasse Throwable oder deren
Unterklassen.
Werfen einer Ausnahme: Bei der Feststellung
eines Fehlers wird (vom Laufzeitsystem oder
vom Programm) ein Ausnahmeobjekt
konstruiert und an das Laufzeitsystem zur
Behandlung übergeben.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
944
Vom Programm geworfene Ausnahme
Parameter für
Diagnose.
public class Program {
public static void main(String[] args) {
throw new RuntimeException("Don’t call main!");
}
}
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
Ein konkreter
Ausnahmetyp
945
Vordefinierte Ausnahmeklassen
Ausnahmen werden
durch Klassen in einer
Vererbungshierarchie
organisiert.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
946
Wichtige Unterklassen von Throwable
Error Klasse und Unterklassen: Kritischer Fehler von
dem kaum zu erwarten ist, dass die Applikation ihn
behandeln kann.
Virtual Machine Error
Exception Klasse und Unterklassen: Mögliche
Ausnahme in der “normalen” Programmausführung.
Solche Ausnahmen können behandelt werden.
IOException
NullPointerException
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
947
Ausnahmen des Laufzeitsystems
IndexOutOfBoundsException: Der Index bei
einem Feldzugriff ist nicht im zulässigen Bereich.
ArrayStoreException: Der Typ des Objektes bei
einem schreibenden Feldzugriff ist nicht zulässig.
NullPointerException: Ein Feldzugriff oder ein
Methodenaufruf auf “null” anstatt einem Objekt.
SecurityException: Der Security Manager weist
einen Verstoss gegen die Sicherheitspolitik ab.
....
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
948
Sprachunterstützung für Ausnahmebehandlung
try {
... // Anweisungen die Ausnahmen werfen könnten
}
catch(AusnahmeTyp name) {
... // Anweisungen welche die Ausnahme behandeln
}
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
949
Ausnahmebehandlung mit try/catch
try {
int value1 = Integer.parseInt(args[0]);
int value2 = Integer.parseInt(args[1]);
int sum = value1 + value2;
System.out.println(value1 + " + " + value2 + " = " + sum);
}
catch (NumberFormatException e) {
System.err.println("Argument(s) not a number");
System.exit(-1);
}
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
950
Sprachunterstützung für Ausnahmebehandlung
einschließlich des finally-Blockes
try {
try-Block
... // Anweisungen
Ausnahme
} catch (AusnahmeTyp name) {
... // Anweisungen
Keine Ausnahme
} finally {
... // Anweisungen
catchBlock
finallyBlock
}
Der catch-Block ist anwendbar für eine Ausnahme a wenn
der Typ von a zuweisungskompatibel mit AusnahmeTyp ist.
Der finally-Block wird auch für den Fall ausgeführt,
dass der catch-Block nicht anwendbar ist oder der
catch oder try-Block continue oder break benutzt.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
951
Mehrere Catch-Klauseln
try {
…
} catch (AusnahmeTyp1 name1) {
…
} catch (AusnahmeTyp2 name2) {
…
} finally {
…
}
Klauseln werden in Definitionsreihefolge geprüft.
Speziellere Ausnahmetypen sind zuerst anzugeben!
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
952
Ein Tabu-Idiom
try {
...
}
catch (Exception x) { }
Konsumiert alle Ausnahmen.
Behandelt keine Ausnahmen.
Verursacht eventuell schwierige Folgefehler.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
953
Propagierung von Ausnahmen
Innerhalb von Hierarchien von Throw-Blöcken
zum unmittelbar umfassenden throw-Block
Im Aufrufkeller
zum nächsten Aufruf mit einem Handler
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
954
Illustration für Propagierung
public class Program {
public static void a() { b(); }
public static void b() { c(); }
public static void c() {
throw new RuntimeException("Safe Our Souls!");
}
public static void main(String[] args) {
try {
a();
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}
java.lang.RuntimeException: Safe Our Souls!
at Program.c(Program.java:9)
at Program.b(Program.java:6)
at Program.a(Program.java:3)
at Program.main(Program.java:13)
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
955
“Stack trace”
Parameter
der Ausnahme
Ausnahmetyp
java.lang.RuntimeException: Safe Our Souls!
at Program.c(Program.java:9)
at Program.b(Program.java:6)
at Program.a(Program.java:3)
at Program.main(Program.java:13)
Methode der
Behandlung
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
956
Aufrufkeller und Ausnahmebehandlung
(für ein neues Szenario)
Methode
wirft Ausnahme
Methode mit
Ausnahme
Methode reicht
Ausnahme durch
Methodenaufruf
Methode ohne
Exception handler
Methode behandelt
Ausnahme
Methodenaufruf
Methode mit
Exception handler
Methodenaufruf
Methode ist
“unbehelligt”
main
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
957
Wichtige Regeln
Konsumiere nur die Ausnahmen, die Du auch
behandelst (behandeln kannst).
Wenn sich eine Ausnahme als nicht behandelbar
herausstellt, nachdem sie bereits abgefangen
wurde, dann muss sie erneut geworfen werden.
Verwende Klassenvererbung um ein System von
Ausnahmen in einer Hierarchie zu organisieren.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
958
Wann sollte man eine Ausnahme werfen
anstatt einfach zurückzukehren?
Pro Ausnahmewurf
Es handelt sich um eine wirkliche Ausnahmesituation.
Der Aufrufer sollte das Problem nicht ignorieren können.
Die Klasse wäre sonst instabil oder inkonsistent.
Con Ausnahmewurf
Das Problem kann allgemein lokal behoben werden.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
959
Ein weiteres Beispiel:
Abhebung vom Konto
Ausnahmesituationen
Grundlegendes Problem (als
Folge eines Bedienfehlers oder
einer Vertragsverletzung)
Betrag ist negativ
IllegalArgumentException
Betrag überzieht Konto
OverdraftException
Anwendungsspezifisches
Problem, welches
behandelt werden sollte.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
960
Abhebung vom Konto
mit Überziehungskontrolle
/**
* Withdraw some money from account.
* Refuse negative amounts as nonsense.
* Throw an exception if an attempt is made to overdraw.
*/
public void withdraw(float amount)
Vordefinierte
{
Ausnahmeklasse
// Precondition
if (amount < 0)
throw new IllegalArgumentException();
if (balance < amount)
throw new OverdraftException();
balance -= amount;
}
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
Programm-definierte
Ausnahmeklasse
961
Programm-definierte Ausnahmenklassen
public class OverdraftException
extends RuntimeException
{ }
Unterklassen von Exception
Konstruktoren
Standardkonstruktor
Konstruktor mit String-Parameter (“Fehlermeldung”)
Weiterer Zustand
Daten für Handler
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
Für
fortgeschrittene
Szenarien
962
Verwendung von
Zusicherungen vs. Ausnahmen
public void withdraw(float amount) {
// Precondition
assert !(
amount < 0
|| balance < amount);
balance -= amount;
}
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
963
Verletzten der
Vorbedingung führt zum
Werfen einer Ausnahme
AssertionError.
Verwendung von
Zusicherungen vs. Ausnahmen
public void withdraw(float amount) {
Spezifischere Ausnahme
als AssertionError
// Precondition
if (amount < 0)
throw new IllegalArgumentException();
if (balance < amount)
throw new OverdraftException();
balance -= amount;
}
Wir werden zeigen, dass wir
den Aufrufer zur Behandlung
zwingen wollen und können!
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
964
Zwang zur Ausnahmebehandlung
Gedankenexperiment
Was wäre wenn wir Aufrufer von “withdraw” zur
Ausnahmebehandlung “ermutigen” (“erzwingen”)
wollen -- soweit es den Versuch der
Kontenüberziehung angeht?
Ein solcher Versuch ist schließlich eine
Ausnahmesituation, auf welche das Programm
vorbereitet sein sollte.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
965
Wir wollen dieses Programm verbieten.
public static void transfer( Account from
, Account to
, float amount) {
to.deposit(amount);
from.withdraw(amount);
}
Der Compiler (das Typsystem) soll den
Programmierer zwingen, den möglichen Fehler zu
behandeln.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
966
Verwendung geprüfter Ausnahmen
public class OverdraftException
extends RuntimeException
{ }
Änderung unserer
ursprünglichen
Ausnahmeklasse
Ungeprüfte Ausnahmen
Sind von RuntimeException abgeleitet
Müssen nicht in Methodensignatur spezifiziert werden
Gelten eher als nicht reparierbar
Geprüfte Ausnahmen
Sind nicht von RuntimeException abgeleitet
Müssen in Methodensignatur spezifiziert werden
Sollten von der Anwendung behandelt werden
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
967
Dieses Programm wird abgewiesen.
public static void transfer( Account from
, Account to
, float amount) {
to.deposit(amount);
from.withdraw(amount);
}
Wir müssen die Ausnahme
OverdraftException entweder
deklarieren oder behandeln.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
968
Eine Behandlung innerhalb der Methode
transfer ist nicht offensichtlich.
public static void transfer( Account from
, Account to
, float amount) {
try {
from.withdraw(amount);
to.deposit(amount);
}
catch (OverdraftException o) {
// ... but what to do?
}
}
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
969
Die Behandlungspflicht ergeht an Aufrufer.
public static void transfer( Account from
, Account to
, float amount)
throws OverdraftException
{
from.withdraw(amount);
to.deposit(amount);
}
Der Compiler (das Typsystem) soll den
Programmierer wenigstens dazu zwingen, die
Ausnahme zu deklarieren.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
970
Die mögliche
Ausnahme wird
explizit deklariert.
Deklaration von werfbaren Ausnahmen
/**
* Withdraw some money from account.
* Refuse negative amounts as nonsense.
* Throw an exception if an attempt is made to overdraw.
*/
public void withdraw(float amount)
throws OverdraftException
{
// Precondition
if (amount < 0)
IllegalArgumentExceptio
n ist eine ungeprüfte
Ausnahmeklasse und
muss deswegen nicht
deklariert werden.
throw new IllegalArgumentException();
if (balance < amount)
throw new OverdraftException();
balance -= amount;
}
Der Compiler (das Typsystem) verlangt die
throws-Deklaration (im Falle einer geprüften
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
971
Geprüft oder ungeprüft?
Sun´s (Oracle’s?) guideline: If a client can reasonably be
expected to recover from an exception, make it a checked
exception. If a client cannot do anything to recover from
the exception, make it an unchecked exception.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
972
Zusammenfassung
Fehler sind unzulässige Programmzustände.
Ausnahmen sind Ereignisse, die den regulären Ablauf abbrechen.
Ausnahmen sind Objekte / Ausnahmetypen sind Klassen.
Sprachunterstützung: try, catch, finally, throw, throws
Von einigen Fehler kann man sich nicht erholen.
Von gewissen Ausnahmen kann man sich erholen.
Ausblick
Syntax von Softwaresprachen
Klausur
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
Ein Zitat zur Fehlerbehandlung
The major difference between a thing that might go wrong and a
thing that cannot possibly go wrong is that when a thing that
cannot possibly go wrong goes wrong it usually turns out to be
impossible to get at or repair.
Douglas Adams [Ada92]
Vergleiche dies mit dem Fehlschlagen
einer Vorbedingung einer Methode.
(C) Ralf Lämmel, OOPM, Universität Koblenz-Landau
974
Herunterladen