Java try-with-resources-Anweisung

Java 9 新特性Neue Funktionen in Java 9

try-with-resources ist ein prägnanter Ansatz zur Ressourcenverwaltung, der in Java 7 eingeführt wurde und sich für Ressourcen eignet, die nach der Verwendung automatisch geschlossen werden müssen (z. B. Dateien, Datenbankverbindungen, Netzwerkverbindungen usw.).

try-with-resources erleichtert das Schließen von Ressourcen, die in try-catch-Anweisungsblöcken verwendet werden. Eine sogenannte Ressource bezieht sich auf ein Objekt, das nach Abschluss des Programms geschlossen werden muss.

Die try-with-resources-Anweisung stellt sicher, dass jede Ressource am Ende der Anweisung geschlossen wird.

Alle Objekte, die die Schnittstelle java.lang.AutoCloseable implementieren (einschließlich aller Objekte, die java.io.Closeable implementieren), können als Ressourcen verwendet werden.

Vorteile:

  • Vereinfachter Code: Beseitigt manuellen Code zum Schließen von Ressourcen und macht die Logik klarer.
  • Weniger Fehler: Behandelt das Schließen von Ressourcen automatisch und vermeidet vergessene Ressourcenschließungen oder die Behandlungfinallyvon Ausnahmen, die im Block auftreten.
  • Verbesserte Leistung: Reduziert Ressourcenlecks und spart Systemressourcen.

Ausführungsablauf

Der Schlüssel zum Verständnis von try-with-resources liegt darin, den Ressourcenlebenszyklus und den Kontrollfluss beim Auftreten von Ausnahmen zu erfassen.

Grundlegende Syntax

Die Syntax von try-with-resources lautet wie folgt:

try (ResourceType resource = new ResourceType()) {
    // 使用资源
} catch (ExceptionType e) {
    // 处理异常
}

Im try-Block deklarierte Ressourcen werden nach Abschluss der Codeausführung automatisch geschlossen und selbst dann sicher geschlossen, wenn eine Ausnahme auftritt.

Verwaltung mehrerer Ressourcen (Schließen in umgekehrter Reihenfolge der Deklaration):

try (Connection  conn = DriverManager.getConnection(url);
     Statement  stmt = conn.createStatement();
     ResultSet  rs   = stmt.executeQuery(sql)) {

    while (rs.next()) {
        System.out.println(rs.getString(1));
    }
} catch (SQLException e) {
    e.printStackTrace();
}

Schließreihenfolge:

rs → stmt → conn(声明顺序的逆序)

Schließreihenfolge:Mehrere Ressourcen werden in umgekehrter Reihenfolge ihrer Deklaration geschlossen, das heißt, später deklarierte Ressourcen werden zuerst geschlossen. Dies entspricht der stackbasierten (LIFO)-Verwaltung und stellt sicher, dass Ressourcen mit Abhängigkeiten korrekt freigegeben werden.

Declaration Phase Declaration / Initialization res1 Connection ① res2 Statement ② res3 ResultSet Execute try block Execute try { ... } Closing Phase Auto-close (Reverse Order) close res3 ResultSet close res2 Statement close res1 Connection Close arrow ③ ④ ⑤ try block to close arrow try block ends

Verwendung der AutoCloseable-Schnittstelle

Jede benutzerdefinierte Klasse, die von try-with-resources verwaltet werden soll, muss nur die Schnittstelle java.lang.AutoCloseable (oder java.io.Closeable) implementieren und deren close()-Methode implementieren.

Beispiel

public class DatabaseConnection implements AutoCloseable {
    private final String url;

    public DatabaseConnection(String url) {
        this.url = url;
        System.out.println("Verbindung hergestellt: " + url);
    }

    public void query(String sql) {
        System.out.println("Abfrage wird ausgeführt: " + sql);
    }

    @Override
    public void close() {
        System.out.println("Verbindung geschlossen: " + url);
        // Zugrunde liegende Verbindungsressourcen freigeben...
    }
}

// Verwendung
try (DatabaseConnection db = new DatabaseConnection("jdbc:mysql://localhost/mydb")) {
    db.query("SELECT * FROM users");
} catch (Exception e) {
    e.printStackTrace();
}

Ausgabe:

连接已建立: jdbc:mysql://localhost/mydb
执行查询: SELECT * FROM users
连接已关闭: jdbc:mysql://localhost/mydb

Ausnahmebehandlung und unterdrückte Ausnahmen

Wenn sowohl die Geschäftslogik im try-Block als auch close() Ausnahmen auslösen, wendet try-with-resources eine spezielle Strategie an: Die Geschäftsausnahme wird als primäre Ausnahme nach oben weitergegeben, während die von close() ausgelöste Ausnahme unterdrückt und an die primäre Ausnahme angehängt wird; sie kann über getSuppressed() abgerufen werden.

try block try { ... } Throws Exception A (Business exception) close() Throws Exception B (Closing exception) Connect try → close Triggers Primary exception Primary exception Exception A Suppressed exception Suppressed exception Exception B Arrow Attach suppressed addSuppressed() catch block catch (Exception e) Catches primary exception A e.getSuppressed() Retrieve suppressed Exception B Connect to catch

Beispiel

try (ResourceWithException res = new ResourceWithException()) {
    res.doSomething();           // Wirft Ausnahme A (Fachausnahme)
} catch (Exception e) {
    System.out.println("Primäre Ausnahme: "  + e.getMessage());
    for (Throwable s : e.getSuppressed()) {   // Ausnahme B abrufen
        System.out.println("Unterdrückte Ausnahme: " + s.getMessage());
    }
}

Ausgabe:

主异常: Exception in doSomething
抑制异常: Exception in close

Hinweis:Bei traditionellem try-finally überschreibt eine Ausnahme im finally-Block die Fachausnahme, wodurch der ursprüngliche Fehler verloren geht. try-with-resources löst diesen klassischen Fallstrick durch den Mechanismus der unterdrückten Ausnahmen.

Java 9 Verbesserung: Wiederverwendung externer Variablen

Vor Java 9 mussten Ressourcen in try-with-resources im try()-Block neu deklariert werden.

Java 9 hat diese Einschränkung entfernt: Solange die Variable effektiv final ist, kann sie direkt in try() referenziert werden, ohne neu deklariert zu werden.

Java 7 / 8 — Muss neu deklariert werden

BufferedReader br = new BufferedReader(new StringReader("hello"));
try (BufferedReader br1 = br) {    // ← Neue Variable br1 muss deklariert werden
    System.out.println(br1.readLine());
}

Java 9+ — Direkte Wiederverwendung

BufferedReader br = new BufferedReader(new StringReader("hello"));
try (br) {                           // ← br direkt verwenden, keine erneute Deklaration nötig
    System.out.println(br.readLine());
}

effektiv final:Wenn eine Variable nach der Initialisierung nicht neu zugewiesen wird, behandelt der Compiler sie automatisch als final. Das Schlüsselwort final muss nicht explizit geschrieben werden.

Vergleich mit try-finally

Dimension try-finally try-with-resources
Codeumfang Mehr — erfordert manuellen Aufruf von close() Weniger — automatisches Schließen
Risiko, close() wegzulassen Hoch — menschliches Übersehen verursacht leicht Ressourcenlecks Null — vom Compiler garantiert
Mehrfache Ressourcenverschachtelung Tiefe Verschachtelung, schlechte Lesbarkeit Durch Semikolon getrennt, flach und klar
Ausnahmebehandlung finally-Ausnahme überschreibt fachliche Ausnahme Mechanismus für unterdrückte Ausnahmen, Informationen vollständig erhalten
Anwendungsbereich Jede Aufräumlogik Ressourcen, die AutoCloseable implementieren

try-finally-Ansatz (ausführlich und fehleranfällig)

BufferedReader br = null;
try {
    br = new BufferedReader(new FileReader("data.txt"));
    String line;
    while ((line = br.readLine()) != null) System.out.println(line);
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (br != null) {               // Benötigt ebenfalls eine Null-Prüfung
        try { br.close(); }        // close selbst kann ebenfalls eine Ausnahme auslösen
        catch (IOException e) { e.printStackTrace(); }
    }
}

try-with-resources-Ansatz (prägnant und sicher)

try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
    String line;
    while ((line = br.readLine()) != null) System.out.println(line);
} catch (IOException e) {
    e.printStackTrace();
}

Häufige Anwendungsfälle

Kategorie Häufige Klassen/Schnittstellen
📁 Datei-I/O FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, FileChannel
🗄 Datenbank Connection, PreparedStatement, Statement, ResultSet, EntityManager
🌐 Netzwerkkommunikation Socket, ServerSocket, HttpURLConnection, InputStream, OutputStream

Wenn Sie mit einer Ressource umgehen, die explizit geschlossen werden muss, sollten Sie try-with-resources gegenüber try-finally bevorzugen. Der Compiler garantiert, dass Ressourcen immer geschlossen werden, der Code ist prägnanter, die Ausnahmeinformationen sind vollständiger, und es ist die bewährte Vorgehensweise für das Java-Ressourcenmanagement.

Java 9 新特性Neue Funktionen in Java 9

Andere Erweiterungen