EMZETT.
Login

try-with-resources

Kurz: Eine try-Variante, die eine Ressource (z. B. eine Datei oder Datenbankverbindung) automatisch schließt, sobald der Block verlassen wird — egal ob normal oder durch eine Exception.

Genauer: Die Ressource wird direkt in den Klammern hinter try deklariert und muss das Interface AutoCloseable implementieren. Vor Java 7 musste das Schließen manuell in einem finally-Block passieren — leicht zu vergessen und fehleranfällig, besonders bei mehreren Ressourcen gleichzeitig.

try (BufferedReader reader = new BufferedReader(new FileReader("datei.txt"))) {
    System.out.println(reader.readLine());
}

Im Detail

// Vor Java 7: manuelles Schließen im finally, leicht zu vergessen
BufferedReader reader = null;
try {
    reader = new BufferedReader(new FileReader("datei.txt"));
    System.out.println(reader.readLine());
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (reader != null) {
        try { reader.close(); } catch (IOException e) { /* auch hier kann's knallen */ }
    }
}
 
// Mit try-with-resources: kompakt, automatisch geschlossen, auch bei Exception
try (BufferedReader reader = new BufferedReader(new FileReader("datei.txt"))) {
    System.out.println(reader.readLine());
} catch (IOException e) {
    e.printStackTrace();
}
 
// Mehrere Ressourcen gleichzeitig, mit Semikolon getrennt:
try (var in = new FileReader("quelle.txt"); var out = new FileWriter("ziel.txt")) {
    // beide werden garantiert geschlossen, in umgekehrter Deklarationsreihenfolge
}

Das alte Muster (oben im ersten Beispiel) zeigt, warum try-with-resources eingeführt wurde: der manuelle finally-Block braucht selbst wieder einen verschachtelten try/catch, weil auch close() eine IOException werfen kann — bei mehreren Ressourcen wird das schnell unübersichtlich und fehleranfällig, und es ist leicht, das Schließen in einem der vielen möglichen Codepfade schlicht zu vergessen. try-with-resources übernimmt das komplett: jede in den Klammern deklarierte Ressource wird garantiert geschlossen, sobald der Block verlassen wird, egal ob normal, durch ein return, oder durch eine Exception — und zwar in umgekehrter Reihenfolge zur Deklaration (die zuletzt geöffnete Ressource wird zuerst geschlossen, analog zu einem Stack).

Eigene Klassen AutoCloseable machen

Voraussetzung ist, dass die Ressource das Interface AutoCloseable (bzw. dessen strengeres Unterinterface Closeable, das close() explizit auf IOException beschränkt) implementiert, das genau eine Methode vorschreibt: close(). Alle Standard-I/O-Klassen wie BufferedReader, FileWriter, Scanner oder Datenbankverbindungen (java.sql.Connection) erfüllen das bereits — man kann aber auch eigene Klassen AutoCloseable implementieren lassen, um sie in try-with-resources verwendbar zu machen:

class Zeitmesser implements AutoCloseable {
    private final long start = System.nanoTime();
    private final String name;
 
    Zeitmesser(String name) { this.name = name; }
 
    @Override
    public void close() {
        long dauerMs = (System.nanoTime() - start) / 1_000_000;
        System.out.println(name + " dauerte " + dauerMs + " ms");
    }
}
 
try (Zeitmesser t = new Zeitmesser("Berechnung")) {
    // beliebiger Code, dessen Laufzeit gemessen werden soll
}
// gibt beim Verlassen des Blocks automatisch die verstrichene Zeit aus

Dieses Muster wird oft für Ressourcen genutzt, die eigentlich nichts mit Dateien zu tun haben — z. B. Zeitmessung, das Sperren/Entsperren eines Locks, oder das Öffnen/Schließen einer Transaktion.

Suppressed Exceptions

Ein subtiler, aber wichtiger Aspekt: Was passiert, wenn SOWOHL der Code im try-Block eine Exception wirft ALS AUCH close() selbst eine Exception wirft? Bei try-with-resources wird die Exception aus dem try-Block als die “primäre” weitergereicht, während die Exception aus close() als “unterdrückt” (suppressed) daran angehängt wird — abrufbar über getSuppressed() auf der primären Exception. Beim alten, manuellen finally-Muster ging die ursprüngliche Exception dagegen oft komplett verloren, weil eine im finally-Block geworfene Exception die aus dem try-Block überschreibt — ein echter, oft übersehener Bug in älterem Code.

Abgrenzung zu normalem try/catch/finally

try-with-resources ersetzt nicht catch/finally generell, sondern ergänzt speziell das Ressourcen-Management: catch-Blöcke für die eigentliche Fehlerbehandlung können weiterhin direkt angehängt werden (wie im Beispiel oben), und ein zusätzlicher finally-Block ist ebenfalls weiterhin erlaubt, für Aufräumarbeiten, die NICHT ressourcenspezifisch sind. Der entscheidende Unterschied zu Exceptions im Allgemeinen: try-with-resources behandelt keine Fehler, sondern garantiert nur, dass Ressourcen unter allen Umständen freigegeben werden.

Siehe auch: Exceptions, BufferedReader, Files, Interface