Programmiertechnik
Ausnahmen
Prof. Dr. Oliver Haase
Oliver Haase
Hochschule Konstanz
1
Motivation
public class Excep1 {
public void doYourJob() {
Scanner scanner = new Scanner(System.in);
System.out.print("a: ");
int a = scanner.nextInt();
System.out.print("b: ");
int b = scanner.nextInt();
System.out.println("a / b = " + a/b);
}
public static void main(String[] args) {
Excep1 instance = new Excep1();
instance.doYourJob();
System.out.println("Job done.");
}
}
Oliver Haase
Hochschule Konstanz
2
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)
Oliver Haase
Hochschule Konstanz
3
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.
Oliver Haase
Hochschule Konstanz
4
Fehlerbehandlungsmethoden
Moderne Programmiersprachen, wie z.B. C++ und Java, verwenden
Ausnahmen (exceptions) für die 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.
Oliver Haase
Hochschule Konstanz
5
integrierte Fehlerbehandlung
C-Stil Fehlerbehandlung in Java:
public class Excep2 {
public int doYourJob() {
Scanner scanner = new Scanner(System.in);
System.out.print("a: ");
int a = scanner.nextInt();
System.out.print("b: ");
int b = scanner.nextInt();
if ( b == 0 )
return -1;
System.out.println("a / b = " + a/b);
return 0;
}
Oliver Haase
Hochschule Konstanz
6
integrierte Fehlerbehandlung
public static void main(String[] args) {
int ret;
Excep2 instance = new Excep2();
if ( ( ret = instance.doYourJob() ) < 0 )
System.out.println("Fehlercode: " + ret);
else
System.out.println("Job done.");
}
}
Konsole
java Excep2
a: 15
b: 0
Fehlercode: -1
Oliver Haase
Hochschule Konstanz
7
Diskussion
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
Fehler sollten die Ausnahme sein unnatürlich, den
Rückgabewert einer Funktion dem Fehlerfall zu widmen
Fehlerbehandlung integriert in "regulären" Code schwer lesbar
Wenn Funktion tatsächlich einen Wert liefern soll, muss entweder
dieser Wert oder der Fehlercode innerhalb eines
Referenztypparameters zurückgegeben werden.
Oliver Haase
Hochschule Konstanz
8
Fehlercode als Referenzparameter
Beispiel: Angenommen, die Methode doYourJob druckt das
Ergebnis der Divsion a/b nicht aus, sondern liefert es als
Ergebniswert zurück:
public class Excep3 {
public int doYourJob(int[] error) {
Scanner scanner = new Scanner(System.in);
System.out.print("a: ");
int a = scanner.nextInt();
System.out.print("b: ");
int b = scanner.nextInt();
}
if ( b == 0 ) {
error[0] = -1;
return -1;
}
error[0] = 0;
return a/b;
Oliver Haase
Hochschule Konstanz
9
integrierte Fehlerbehandlung
}
public static void main(String[] args) {
Excep3 instance = new Excep3();
int[] error = new int[1];
int ret = instance.doYourJob(error);
if ( error[0] == -1 )
System.out.println("Fehlercode: " + error[0]);
else {
System.out.println("a / b = " + ret);
System.out.println("Job done.");
}
}
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…
Oliver Haase
Hochschule Konstanz
10
Ausnahmen/Exceptions
Trennung von regulärem Code und Fehlerbehandlung.
Wenn Ausnahmesituaton 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.
Oliver Haase
Hochschule Konstanz
11
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()
Oliver Haase
Hochschule Konstanz
12
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.
Oliver Haase
Hochschule Konstanz
13
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 1 oder mehreren catch-Blöcken.
Oliver Haase
Hochschule Konstanz
14
Abfangen von Exceptions
Beispiel:
public void doYourJob() {
Scanner scanner = new Scanner(System.in);
System.out.print("a: ");
int a = scanner.nextInt();
System.out.print("b: ");
int b = scanner.nextInt();
}
try {
System.out.println("a/b = " + a/b);
}
catch(ArithmeticException e) {
System.out.println("Wir haben da ein Problem: "
+ e.getMessage());
System.out.println(
"Das haetten Sie nicht tun sollen...");
}
Oliver Haase
Hochschule Konstanz
15
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!
Oliver Haase
Hochschule Konstanz
16
Beispiel – Daten aus Datei lesen
Berechnung des arithmetischen Mittelwerts einer Menge ganzer
Zahlen.
Die Zahlen stehen in einer Datei vals.txt, und zwar genau eine
Zahl pro Zeile, gefolgt von einem Zeilenumbruch.
Beispiel:
Inhalt der Datei vals.txt
2
4
1
0
(Mittelwert: 1.75)
Oliver Haase
Hochschule Konstanz
17
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 f = new FileReader("vals.txt");
Beachte: Mit einem FileReader-Objekt kann man eine Datei nur
zeichenweise einlesen.
Oliver Haase
Hochschule Konstanz
18
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 FileReaderObjekts:
BufferedReader b = new BufferedReader(f);
Beide Anweisungen können zusammengefasst werden:
BufferedReader b =
new BufferedReader(new FileReader("vals.txt"));
Damit sieht der 1. Lösungsversuch wie folgt aus:
Oliver Haase
Hochschule Konstanz
19
Beispiel – Daten aus Datei lesen
import java.io.*;
public class Mittelwert {
private static int anzahl = 0;
public static int parse(String s) {
anzahl++;
return Integer.parseInt(s);
}
Fortsetzung auf nächster Folie…
Oliver Haase
Hochschule Konstanz
20
Beispiel – Daten aus Datei lesen
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Dateiname: ");
String fileName = scanner.next();
BufferedReader datei =
new BufferedReader(new FileReader(fileName));
double mittel = 0.0;
String line = datei.readLine();
while ( line != null ) {
mittel += parse(line);
line = datei.readLine();
}
mittel /= anzahl;
System.out.println("Mittelwert: " + mittel);
}
}
Oliver Haase
Hochschule Konstanz
21
Beispiel – Daten aus Datei lesen
Aber: Der Versuch, die Klasse zu übersetzen
(javac Mittelwert.java) liefert folgende Fehlermeldung:
Konsole
Mittelwert.java:16: unreported exception
java.io.FileNotFoundException; must be caught or
declared to be thrown
new BufferedReader(new FileReader(fileName));
^
Mittelwert.java:18: unreported exception
java.io.IOException; must be caught or declared to
be thrown
String line = datei.readLine();
^
Mittelwert.java:21: unreported exception
java.io.IOException; must be caught or declared to
be thrown
line = datei.readLine();
^
Oliver Haase
Hochschule Konstanz
22
Beispiel – Daten aus Datei lesen
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Dateiname: ");
FileNotFoundException
String fileName = scanner.next();
möglich
BufferedReader datei =
new BufferedReader(new FileReader(fileName));
double mittel = 0.0;
String line = datei.readLine();
IOException
while ( line != null ) {
möglich
mittel += parse(line);
line = datei.readLine();
}
mittel /= anzahl;
System.out.println("Mittelwert: " + mittel);
}
}
Oliver Haase
Hochschule Konstanz
23
Beispiel – Daten aus Datei lesen
Mögliche Lösung: throws-Klausel im Kopf der main-Methode:
import java.io.*;
import java.util.Scanner;
public class Mittelwert2 {
private static int anzahl = 0;
public static int parse(String s) {
…
}
public static void main(String[] args)
throws FileNotFoundException, IOException {
...
}
}
Effekt: Reicht die Exception durch zur aufrufenden Methode, in
diesem Fall das Java-Laufzeitsystem, das das Programm mit einer
Fehlermeldung abbricht.
Oliver Haase
Hochschule Konstanz
24
Beispiel – Daten aus Datei lesen
Konsole
java Mittelwert2
Datei: bals.txt
Exception in thread "main" java.io.FileNotFoundException:
bals.txt (Das System kann die angegebene Datei nicht
finden)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at java.io.FileInputStream.<init>(Unknown Source)
at java.io.FileReader.<init>(Unknown Source)
at Mittelwert.main(Mittelwert2.java:16)
Oliver Haase
Hochschule Konstanz
25
Beispiel – Daten aus Datei lesen
Alternative Lösung: Exceptions abfangen:
public static void main(String[] args) {
BufferedReader datei = null;
Scanner scanner = new Scanner(System.in);
boolean success;
do {
System.out.println("Dateiname: ");
String fileName = scanner.next("Dateiname: ");
System.out.println("Datei: " + fileName);
try {
datei =
new BufferedReader(new FileReader(fileName));
success = true;
}
catch ( FileNotFoundException e ) {
success = false;
}
} while ( !success );
Oliver Haase
Hochschule Konstanz
26
Beispiel – Daten aus Datei lesen
double mittel = 0.0;
}
try {
String line = datei.readLine();
while ( line != null ) {
mittel += parse(line);
line = datei.readLine();
}
mittel /= anzahl;
System.out.println("Mittelwert: " + mittel);
}
catch ( IOException e ) {
System.out.println("Fehler beim Einlesen");
System.exit(0);
}
Oliver Haase
Hochschule Konstanz
27
Have an
exceptionally nice
cup of coffee!
Oliver Haase
Hochschule Konstanz
28