Call-Stack
Der Call-Stack-Mechanismus
- Ausnahmen werden entlang der Aufrufhierarchie (call stack) propagiert
- Wenn eine Ausnahme nicht von einem
try
-catch
-Block behandelt wird, wird sie an den Aufrufer weitergegeben - Gelangt die Ausnahme bis zur main-Methode und wird dort nicht behandelt, wird das Programm abgebrochen
- Hierdurch kann die Ausnahme bis zu demjenigen wandern, der sie beheben kann
Beispiel: Call-Stack-Mechanismus
Exception in thread "main" java.io.FileNotFoundException:
/tmp/input (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:106)
at java.io.FileInputStream.<init>(FileInputStream.java:66)
at pr2.CallStack.aggregate(CallStack.java:26)
at pr2.CallStack.writeData(CallStack.java:17)
at pr2.CallStack.mergeData(CallStack.java:22)
at pr2.CallStack.main(CallStack.java:9)
Das Ausnahmen in einer Methode gefangen werden können, wurde bereits gezeigt. Was passiert wenn sie nicht gefangen werden? Hierfür gibt es in Java einen Mechanismus (Call-Stack-Mechanismus), der dafür sorgt, dass die Ausnahme an den Aufrufer der Methode weitergeleitet wird. Behandelt dieser die Ausnahme ebenfalls nicht, wird sie an dessen Aufrufer weitergegeben etc.
Behandelt keine Methode in der Aufrufhierarchie die Ausnahme, so kommt sie letztendlich immer in der main-Methode an. Wird sie auch dort nicht behandelt, wird das Programm abgebrochen und der Fehler wird auf der Console ausgegeben.
public static void main(String[] args) throws IOException {
mergeData("/tmp/input", "/tmp/output");
}
public static void mergeData(String inFile, String outFile) throws IOException {
writeData(inFile, outFile);
}
public static void writeData(String inFile, String outFile) throws IOException {
aggregate(5, 5, inFile);
}
public static int aggregate(int a, int b, String inFile) throws IOException {
FileInputStream f = new FileInputStream(inFile);
return 1;
}
Wenn man ein Programm betrachtet, in dem Ausnahmen vorkommen können, muss man sich immer Fragen, an welche Stelle die Ursache für die Ausnahme liegt. Dies muss nicht zwingend die Stelle sein, an der die Ausnahme auftritt.
Hier ist eindeutig die Main-Methode für den Fehler verantwortlich, da sie die Dateinamen an die folgenden Methoden übergibt. Insofern ist die aggregate
-Methode unschuldig an der FileNotFoundException
, die in ihr entstehen wird, wenn es die Datei /tmp/input
gar nicht gibt. Sie bekommt den Namen der Datei übergeben und kann nichts dagegen tun, wenn die Datei nicht existiert.
public static void main(String[] args) throws IOException {
mergeData(args[0], "/tmp/output");
}
public static void mergeData(String inFile, String outFile) throws IOException {
writeData(inFile, outFile);
}
public static void writeData(String inFile, String outFile) throws IOException {
aggregate(5, 5, inFile);
}
public static int aggregate(int a, int b, String inFile) throws IOException {
FileInputStream f = new FileInputStream(inFile);
return 1;
}
In diesem Fall ist der/die Benutzer:in für den Fehler verantwortlich, weil er einen ungültigen Dateinamen auf der Konsole angegeben hat.
Eine gute Implementierung der Fehlerbehandlung in der Main-Methode sähe ungefähr wie folgt aus:
public static void main(String[] args) {
if (args.length < 1) {
System.err.println("Bitte Dateinamen angeben.");
System.exit(4);
}
try {
mergeData(args[0], "/tmp/output");
} catch (IOException e) {
System.err.printf("Datei %s gibt es nicht%n%n", args[0]);
}
}
public static void mergeData(String inFile, String outFile)
throws IOException {
writeData(inFile, outFile);
}
public static void writeData(String inFile, String outFile) throws IOException {
aggregate(5, 5, inFile);
}
public static int aggregate(int a, int b, String inFile) throws IOException {
FileInputStream f = new FileInputStream(inFile);
return 1;
}
public static void main(String[] args) throws IOException {
mergeData("/tmp/input", "/tmp/output");
}
public static void mergeData(String inFile, String outFile) throws IOException {
writeData(outFile);
}
public static void writeData(String outFile) throws IOException {
aggregate(5, 5);
}
public static int aggregate(int a, int b) throws IOException {
FileInputStream f = new FileInputStream("/tmp/input");
return 1;
}
In diesem Beispiel liegt die Verantwortung für den Fehler in der aggregate()
-Methode, da der Dateiname dort festgelegt wird. Sie müsste den Fehler also selbst behandeln und dürfte ihn nicht an die aufrufenden Methoden weitergeben.