Zum Inhalt springen
Java Anfänger 25 min

try/catch/finally

Exception Handling in Java: try/catch/finally, Multi-Catch, try-with-resources und Best Practices für robuste Fehlerbehandlung.

Aktualisiert:

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

Szenariotrycatchfinally
Kein FehlerJaNeinJa
Exception gefangenBis FehlerJaJa
Exception nicht gefangenBis FehlerNeinJa (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!

Zurück zum Java Kurs