Kurz: Wenn etwas schiefgeht (Datei fehlt, Division durch 0, ungültige Eingabe), löst Java eine Ausnahme (Exception) aus. Sie bricht den normalen Ablauf ab und springt zum nächsten passenden catch.
Teil des Kurses Java
Wenn etwas schiefgeht (Datei fehlt, Division durch 0, ungültige Eingabe), löst Java eine Ausnahme (Exception) aus. Sie bricht den normalen Ablauf ab und springt zum nächsten passenden catch.
public class Fangen {
public static void main(String[] args) {
try {
System.out.println("vorher");
int x = Integer.parseInt("abc");
System.out.println("wird nie erreicht " + x);
} catch (NumberFormatException e) {
System.out.println("Ungültige Zahl: " + e.getMessage());
} finally {
System.out.println("läuft immer");
}
System.out.println("Programm läuft weiter");
}
}Ausgabe:
vorher
Ungültige Zahl: For input string: "abc"
läuft immer
Programm läuft weiterMehrere catch-Blöcke
public class Mehrere {
static void test(int variante) {
try {
switch (variante) {
case 0 -> System.out.println(10 / (variante));
case 1 -> { String s = null; s.length(); }
case 2 -> { int[] a = new int[2]; a[5] = 1; }
case 3 -> Integer.parseInt("x");
default -> throw new IllegalStateException("Zustand " + variante);
}
} catch (ArithmeticException | NullPointerException e) { // mehrere Typen
System.out.println("Rechen/Null: " + e.getClass().getSimpleName());
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Index: " + e.getMessage());
} catch (RuntimeException e) { // allgemeiner zuletzt
System.out.println("Sonstiges: " + e.getClass().getSimpleName() + " " + e.getMessage());
}
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) test(i);
}
}Ausgabe:
Rechen/Null: ArithmeticException
Rechen/Null: NullPointerException
Index: Index 5 out of bounds for length 2
Sonstiges: NumberFormatException For input string: "x"
Sonstiges: IllegalStateException Zustand 4Reihenfolge: spezifisch vor allgemein. Ein allgemeiner Typ (Exception) vor einem speziellen würde diesen verdecken (Compilerfehler).
Die Hierarchie
Throwable
├─ Error schwere JVM-Fehler (OutOfMemoryError, StackOverflowError), nicht fangen
└─ Exception
├─ RuntimeException ungeprüft (unchecked): Programmierfehler
│ ├─ NullPointerException, IllegalArgumentException, IllegalStateException
│ ├─ IndexOutOfBoundsException, ArithmeticException, ClassCastException
│ └─ NumberFormatException, UnsupportedOperationException
└─ andere Exceptions geprüft (checked): IOException, SQLException ...| Art | Beispiele | Pflicht? |
|---|---|---|
| Checked (geprüft) | IOException, SQLException | musst du fangen oder mit throws weitergeben |
Unchecked (RuntimeException) | NullPointerException, IllegalArgumentException | keine Pflicht |
throws und throw
import java.io.*;
public class Werfen {
static double teile(double a, double b) {
if (b == 0) throw new ArithmeticException("Division durch 0");
return a / b;
}
static String lese(String pfad) throws IOException { // checked: Aufrufer muss reagieren
try (BufferedReader r = new BufferedReader(new FileReader(pfad))) {
return r.readLine();
}
}
public static void main(String[] args) {
try {
System.out.println(teile(10, 4));
System.out.println(teile(1, 0));
} catch (ArithmeticException e) {
System.out.println("Fehler: " + e.getMessage());
}
try {
lese("gibt-es-nicht.txt");
} catch (IOException e) {
System.out.println("IO: " + e.getClass().getSimpleName());
}
}
}Ausgabe:
2.5
Fehler: Division durch 0
IO: FileNotFoundExceptiontry-with-resources
Dateien, Verbindungen und Streams müssen geschlossen werden. Mit try (...) passiert das automatisch, auch bei Fehlern. Das Objekt muss AutoCloseable sein:
public class Ressource {
static class Verbindung implements AutoCloseable {
final String name;
Verbindung(String name) { this.name = name; System.out.println("öffne " + name); }
void sende(String s) { System.out.println(name + " sendet " + s); if (s.isEmpty()) throw new IllegalArgumentException("leer"); }
@Override public void close() { System.out.println("schließe " + name); }
}
public static void main(String[] args) {
try (Verbindung a = new Verbindung("A"); Verbindung b = new Verbindung("B")) {
a.sende("Hallo");
b.sende("");
} catch (IllegalArgumentException e) {
System.out.println("Fehler: " + e.getMessage());
}
}
}Ausgabe:
öffne A
öffne B
A sendet Hallo
B sendet
schließe B
schließe A
Fehler: leerGeschlossen wird in umgekehrter Reihenfolge der Öffnung.
Eigene Ausnahmen
public class Eigene {
static class GuthabenException extends Exception {
private final double fehlbetrag;
GuthabenException(String nachricht, double fehlbetrag) {
super(nachricht);
this.fehlbetrag = fehlbetrag;
}
double getFehlbetrag() { return fehlbetrag; }
}
static double abheben(double stand, double betrag) throws GuthabenException {
if (betrag > stand) throw new GuthabenException("Zu wenig Guthaben", betrag - stand);
return stand - betrag;
}
public static void main(String[] args) {
try {
System.out.println(abheben(100, 30));
System.out.println(abheben(100, 130));
} catch (GuthabenException e) {
System.out.println(e.getMessage() + ", es fehlen " + e.getFehlbetrag());
}
}
}Ausgabe:
70.0
Zu wenig Guthaben, es fehlen 30.0Ursache mitgeben (Exception Chaining)
public class Verkettet {
static void lade() {
try {
Integer.parseInt("kaputt");
} catch (NumberFormatException e) {
throw new IllegalStateException("Konfiguration ungültig", e); // Ursache bleibt erhalten
}
}
public static void main(String[] args) {
try { lade(); }
catch (IllegalStateException e) {
System.out.println(e.getMessage() + " <- " + e.getCause().getClass().getSimpleName());
}
}
}Ausgabe:
Konfiguration ungültig <- NumberFormatExceptionDer Stacktrace
Nicht gefangene Ausnahmen beenden das Programm und zeigen den Stacktrace: die Kette der Methodenaufrufe bis zur Fehlerstelle.
public class Absturz {
static int teile(int a, int b) { return a / b; }
public static void main(String[] args) {
System.out.println(teile(1, 0));
}
}Fehlermeldung:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Absturz.teile(Absturz.java:2)
at Absturz.main(Absturz.java:4)Lies ihn von oben: Die erste Zeile nennt den Fehler, die nächste die Stelle, wo er auftrat.
Gute Praxis
- Nur fangen, was du behandeln kannst. Ein leeres
catchist fast immer ein Fehler. - Fange nicht
ExceptionoderThrowablepauschal. - Prüfe Eingaben vorher (
IllegalArgumentException), statt Fehler abzufangen. - Gib Ausnahmen aussagekräftige Meldungen und die Ursache mit.
- Nutze
try-with-resourcesfür alles, was geschlossen werden muss. - Logge Fehler (mit Stacktrace), statt
e.printStackTrace()in Produktionscode.
Merke
try { } catch (Typ e) { } finally { };throw new ...löst aus,throwsmeldet an- Checked Exceptions musst du behandeln,
RuntimeExceptions nicht - Spezifische
catch-Blöcke vor allgemeinen try-with-resourcesschließt Ressourcen automatisch- Eigene Ausnahmen erweitern
ExceptionoderRuntimeException; Ursache mitgeben
Übungsaufgabe
Schreibe eine Methode leseZahl(String), die bei ungültiger Eingabe eine eigene Ausnahme wirft, und fange sie in einer Schleife über mehrere Eingaben ab.
Quiz zur Selbstkontrolle
Wann läuft der finally-Block?
- Immer, mit oder ohne Ausnahme (richtig)
- Nur bei Fehlern
- Nur ohne Fehler
- Nie
Was ist eine Checked Exception?
- Eine Ausnahme, die man fangen oder mit throws deklarieren muss (richtig)
- Eine Ausnahme ohne Meldung
- Eine Ausnahme der JVM
- Eine, die den Compiler stoppt
Wozu dient try-with-resources?
- Ressourcen werden automatisch geschlossen (richtig)
- Es fängt alle Fehler
- Es beschleunigt den Code
- Es verhindert Ausnahmen
Weiter im Kurs
Zurück: Records, Enums und versiegelte Typen
Weiter: Generics
Alle Kapitel: Java im Überblick