try/catch/finally
Exception Handling in Java: try/catch/finally, Multi-Catch, try-with-resources und Best Practices für robuste Fehlerbehandlung.
try/catch/finally
Du weisst jetzt, was Exceptions sind. In diesem Kapitel lernst du, wie du sie auffaengst und sinnvoll behandelst — damit dein Programm nicht abstuerzt, sondern elegant mit Fehlern umgeht.
try-catch Grundlagen
try {
// Code, der eine Exception ausloesen koennte
var zahl = Integer.parseInt("abc");
System.out.println("Zahl: " + zahl);
} catch (NumberFormatException e) {
// Was tun, wenn die Exception auftritt
System.out.println("Ungueltige Zahl: " + e.getMessage());
}
System.out.println("Programm laeuft weiter!"); // Wird ausgefuehrt!
Ausgabe:
Ungueltige Zahl: For input string: "abc"
Programm laeuft weiter!
Aufbau
try {
// Gefaehrlicher Code
} catch (ExceptionTyp variablenName) {
// Fehlerbehandlung
}
Ohne try-catch wuerde das Programm an der Stelle abstuerzen. Mit try-catch faengt es den Fehler auf und macht weiter.
Mehrere catch-Bloecke
Du kannst verschiedene Exceptions unterschiedlich behandeln:
try {
var scanner = new Scanner(System.in);
System.out.print("Gib einen Index ein: ");
var index = scanner.nextInt();
int[] zahlen = {10, 20, 30};
System.out.println("Wert: " + zahlen[index]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Index ausserhalb des Arrays! " + e.getMessage());
} catch (InputMismatchException e) {
System.out.println("Keine gueltige Zahl eingegeben!");
} catch (Exception e) {
System.out.println("Unerwarteter Fehler: " + e.getMessage());
}
Reihenfolge wichtig: Von spezifisch zu allgemein! Die speziellste Exception muss zuerst stehen.
// FALSCH: Exception faengt alles -- die anderen werden nie erreicht
// try { ... }
// catch (Exception e) { } // Faengt alles!
// catch (IOException e) { } // Nie erreicht! Kompilierfehler!
// RICHTIG: Spezifisch zuerst
try { /* ... */ }
catch (FileNotFoundException e) { } // Spezifisch
catch (IOException e) { } // Allgemeiner
catch (Exception e) { } // Am allgemeinsten
Multi-Catch (Java 7+)
Wenn mehrere Exceptions gleich behandelt werden sollen:
try {
// Code
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
System.out.println("Eingabefehler: " + e.getMessage());
}
finally — Immer ausfuehren
Der finally-Block wird immer ausgefuehrt — egal ob eine Exception auftrat oder nicht:
Scanner scanner = null;
try {
scanner = new Scanner(System.in);
var zahl = scanner.nextInt();
System.out.println("Zahl: " + zahl);
} catch (InputMismatchException e) {
System.out.println("Keine gueltige Zahl!");
} finally {
// Wird IMMER ausgefuehrt
if (scanner != null) {
scanner.close();
}
System.out.println("Scanner geschlossen.");
}
try-catch-finally Ablauf
| Szenario | try | catch | finally |
|---|---|---|---|
| Kein Fehler | Ja | Nein | Ja |
| Exception gefangen | Bis Fehler | Ja | Ja |
| Exception nicht gefangen | Bis Fehler | Nein | Ja (dann Absturz) |
try-with-resources (Java 7+)
Fuer Ressourcen (Dateien, Verbindungen, Scanner) gibt es eine elegantere Loesung. Die Ressource wird automatisch geschlossen:
// Statt:
Scanner scanner = null;
try {
scanner = new Scanner(System.in);
// ...
} finally {
if (scanner != null) scanner.close();
}
// Schreibe:
try (var scanner = new Scanner(System.in)) {
var zahl = scanner.nextInt();
System.out.println("Zahl: " + zahl);
} catch (InputMismatchException e) {
System.out.println("Keine gueltige Zahl!");
}
// scanner wird automatisch geschlossen!
Mit Dateien
import java.io.*;
import java.nio.file.*;
// Datei lesen
try (var reader = Files.newBufferedReader(Path.of("datei.txt"))) {
String zeile;
while ((zeile = reader.readLine()) != null) {
System.out.println(zeile);
}
} catch (IOException e) {
System.out.println("Fehler beim Lesen: " + e.getMessage());
}
// Moderne Alternative mit Files.readString()
try {
var inhalt = Files.readString(Path.of("datei.txt"));
System.out.println(inhalt);
} catch (IOException e) {
System.out.println("Fehler: " + e.getMessage());
}
Mehrere Ressourcen
try (
var reader = Files.newBufferedReader(Path.of("eingabe.txt"));
var writer = Files.newBufferedWriter(Path.of("ausgabe.txt"))
) {
String zeile;
while ((zeile = reader.readLine()) != null) {
writer.write(zeile.toUpperCase());
writer.newLine();
}
} catch (IOException e) {
System.out.println("IO-Fehler: " + e.getMessage());
}
Exception-Informationen nutzen
try {
int[] arr = {1, 2, 3};
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
// Fehlermeldung
System.out.println("Nachricht: " + e.getMessage());
// Stack Trace (fuer Debugging)
e.printStackTrace();
// Exception-Klasse
System.out.println("Typ: " + e.getClass().getName());
}
throws — Exceptions weitergeben
Statt eine Exception selbst zu behandeln, kannst du sie an den Aufrufer weitergeben:
// Diese Methode behandelt die Exception NICHT selbst
public static String leseDatei(String pfad) throws IOException {
return Files.readString(Path.of(pfad));
}
// Der Aufrufer MUSS die Exception behandeln
public static void main(String[] args) {
try {
var inhalt = leseDatei("daten.txt");
System.out.println(inhalt);
} catch (IOException e) {
System.out.println("Konnte Datei nicht lesen: " + e.getMessage());
}
}
Praktische Beispiele
Robuste Zahleneingabe
import java.util.Scanner;
public class RobusteEingabe {
static int leseGanzzahl(Scanner scanner, String prompt) {
while (true) {
System.out.print(prompt);
try {
return Integer.parseInt(scanner.nextLine());
} catch (NumberFormatException e) {
System.out.println("Bitte eine gueltige Ganzzahl eingeben!");
}
}
}
public static void main(String[] args) {
try (var scanner = new Scanner(System.in)) {
var alter = leseGanzzahl(scanner, "Dein Alter: ");
System.out.println("Du bist " + alter + " Jahre alt.");
}
}
}
Datei sicher lesen
import java.nio.file.*;
static List<String> ladeZeilen(String pfad) {
try {
return Files.readAllLines(Path.of(pfad));
} catch (NoSuchFileException e) {
System.out.println("Datei nicht gefunden: " + pfad);
return List.of();
} catch (IOException e) {
System.out.println("Fehler beim Lesen: " + e.getMessage());
return List.of();
}
}
Best Practices
1. Fange spezifische Exceptions
// SCHLECHT: Zu allgemein
try { /* ... */ }
catch (Exception e) { System.out.println("Irgendein Fehler"); }
// GUT: Spezifisch
try { /* ... */ }
catch (FileNotFoundException e) { System.out.println("Datei nicht gefunden"); }
catch (IOException e) { System.out.println("IO-Fehler: " + e.getMessage()); }
2. Leere catch-Bloecke vermeiden
// SCHLECHT: Exception wird verschluckt
try { /* ... */ }
catch (Exception e) { } // Still und heimlich ignoriert!
// GUT: Mindestens loggen
try { /* ... */ }
catch (Exception e) {
System.err.println("Fehler: " + e.getMessage());
// Oder: logger.error("Fehler", e);
}
3. try-with-resources verwenden
// SCHLECHT: Manuelles Schliessen
Scanner s = new Scanner(System.in);
try {
// ...
} finally {
s.close();
}
// GUT: try-with-resources
try (var s = new Scanner(System.in)) {
// ... automatisch geschlossen
}
4. Exceptions nicht fuer Kontrollfluss
// SCHLECHT: Exception als if-else-Ersatz
try {
var wert = Integer.parseInt(text);
} catch (NumberFormatException e) {
// Text ist keine Zahl -- normaler Ablauf
}
// GUT: Vorher pruefen (wenn moeglich)
if (text.matches("-?\\d+")) {
var wert = Integer.parseInt(text);
}
Uebungen
Uebung 1: Sicherer Taschenrechner
Schreibe einen Taschenrechner, der alle moeglichen Fehler abfaengt: ungueltige Zahlen, Division durch 0, unbekannter Operator.
Uebung 2: Datei-Kopierer
Schreibe ein Programm, das eine Datei liest und in eine andere schreibt. Behandle alle moeglichen Exceptions sinnvoll.
Uebung 3: Wiederholte Eingabe
Schreibe eine Methode, die den Benutzer solange nach einer Zahl zwischen 1 und 100 fragt, bis er eine gueltige Eingabe macht.
Uebung 4: Konfigurationsdatei
Schreibe eine Methode, die eine Konfigurationsdatei (Key=Value-Format) einliest und als Map zurueckgibt. Behandle fehlende Dateien und ungueltige Formate.
Was kommt als Naechstes?
In der naechsten Lektion lernst du, wie du eigene Exceptions erstellst — maßgeschneidert fuer deine Anwendung.
Zusammenfassung
- try-catch faengt Exceptions auf und verhindert Programmabstuerze
- Mehrere catch-Bloecke behandeln verschiedene Exceptions unterschiedlich
- Multi-catch (
catch (A | B e)) vereinfacht gleiche Behandlung - finally wird immer ausgefuehrt (Aufraeumen von Ressourcen)
- try-with-resources schliesst Ressourcen automatisch (bevorzugen!)
- throws gibt Exceptions an den Aufrufer weiter
- Fange spezifische Exceptions und vermeide leere catch-Bloecke
Pro-Tipp: Verwende immer try-with-resources statt try-finally fuer Ressourcen wie Scanner, FileReader oder Datenbankverbindungen. Es ist kuerzer, sicherer und funktioniert auch korrekt, wenn sowohl im try- als auch im close()-Aufruf eine Exception auftritt. In IntelliJ warnt dich eine Inspektion automatisch, wenn du eine Ressource nicht mit try-with-resources oeffnest!