Java try-with-resources-Anweisung
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 Behandlung
finallyvon 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.
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
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.
Beispiel
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
try (BufferedReader br1 = br) { // ← Neue Variable br1 muss deklariert werden
System.out.println(br1.readLine());
}
Java 9+ — Direkte Wiederverwendung
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)
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)
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.
Andere Erweiterungen
Neue Funktionen in Java 9