Java try-with-resources Statement
try-with-resources is a concise resource management approach introduced in Java 7, suitable for resources that need to be automatically closed after use (such as files, database connections, network connections, etc.).
try-with-resources makes it easy to close resources used in try-catch statement blocks. A so-called resource refers to an object that must be closed after the program completes.
The try-with-resources statement ensures that each resource is closed at the end of the statement.
All objects that implement the java.lang.AutoCloseable interface (which includes all objects implementing java.io.Closeable) can be used as resources.
Advantages:
- Simplified code: Eliminates manual resource-closing code, making the logic clearer.
- Fewer errors: Automatically handles resource closing, avoiding forgotten resource closures or handling
finallyexceptions that occur in the block. - Improved performance: Reduces resource leaks and saves system resources.
Execution Flow
The key to understanding try-with-resources lies in grasping the resource lifecycle and the control flow when exceptions occur.
Basic Syntax
The try-with-resources syntax is as follows:
try (ResourceType resource = new ResourceType()) {
// 使用资源
} catch (ExceptionType e) {
// 处理异常
}
Resources declared in the try block are automatically closed after the code finishes executing, and are safely closed even when an exception occurs.
Multiple Resource Management (Closed in Reverse Order of Declaration):
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();
}
Close order:
rs → stmt → conn(声明顺序的逆序)
Close order:Multiple resources are closed in reverse order of their declaration, meaning resources declared later are closed first. This is consistent with stack-based (LIFO) management, ensuring that resources with dependencies are released correctly.
Using the AutoCloseable Interface
Any custom class that wants to be managed by try-with-resources only needs to implement the java.lang.AutoCloseable (or java.io.Closeable) interface and implement its close() method.
Example
private final String url;
public DatabaseConnection(String url) {
this.url = url;
System.out.println("Connection established: " + url);
}
public void query(String sql) {
System.out.println("Executing query: " + sql);
}
@Override
public void close() {
System.out.println("Connection closed: " + url);
// Release underlying connection resources...
}
}
// Usage
try (DatabaseConnection db = new DatabaseConnection("jdbc:mysql://localhost/mydb")) {
db.query("SELECT * FROM users");
} catch (Exception e) {
e.printStackTrace();
}
Output:
连接已建立: jdbc:mysql://localhost/mydb 执行查询: SELECT * FROM users 连接已关闭: jdbc:mysql://localhost/mydb
Exception Handling and Suppressed Exceptions
When both the business logic in the try block and close() throw exceptions, try-with-resources adopts a special strategy: the business exception propagates upward as the primary exception, while the exception thrown by close() is suppressed and attached to the primary exception, retrievable via getSuppressed().
Example
res.doSomething(); // Throws Exception A (business exception)
} catch (Exception e) {
System.out.println("Primary exception: " + e.getMessage());
for (Throwable s : e.getSuppressed()) { // Retrieve Exception B
System.out.println("Suppressed exception: " + s.getMessage());
}
}
Output:
主异常: Exception in doSomething 抑制异常: Exception in close
Note:In traditional try-finally, an exception in the finally block overrides the business exception, causing the original error to be lost. try-with-resources solves this classic pitfall through the suppressed exception mechanism.
Java 9 Enhancement: Reusing External Variables
Before Java 9, try-with-resources required resources to be redeclared in the try() block.
Java 9 removed this restriction: as long as the variable is effectively final, it can be referenced directly in try() without redeclaration.
Java 7 / 8 — Must Redeclare
try (BufferedReader br1 = br) { // ← Must declare a new variable br1
System.out.println(br1.readLine());
}
Java 9+ — Direct Reuse
try (br) { // ← Use br directly, no redeclaration needed
System.out.println(br.readLine());
}
effectively final:If a variable is not reassigned after initialization, the compiler automatically treats it as final. There is no need to explicitly write the final keyword.
Comparison with try-finally
| Dimension | try-finally | try-with-resources |
|---|---|---|
| Code volume | More — requires manually calling close() | Less — automatic closing |
| Risk of omitting close() | High — human oversight easily causes resource leaks | Zero — guaranteed by the compiler |
| Multiple resource nesting | Deep nesting, poor readability | Semicolon-separated, flat and clear |
| Exception handling | finally exception overrides business exception | Suppressed exception mechanism, information fully preserved |
| Applicable scope | Any cleanup logic | Resources implementing AutoCloseable |
try-finally Approach (Verbose and Error-Prone)
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) { // Also needs null check
try { br.close(); } // close itself may also throw an exception
catch (IOException e) { e.printStackTrace(); }
}
}
try-with-resources Approach (Concise and Safe)
String line;
while ((line = br.readLine()) != null) System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
Common Use Cases
| Category | Common Classes/Interfaces |
|---|---|
| 📁 File I/O | FileInputStream、FileOutputStream、BufferedReader、BufferedWriter、FileChannel |
| 🗄 Database | Connection、PreparedStatement、Statement、ResultSet、EntityManager |
| 🌐 Network Communication | Socket、ServerSocket、HttpURLConnection、InputStream、OutputStream |
When dealing with any resource that requires explicit closing, prefer try-with-resources over try-finally. The compiler guarantees that resources are always closed, the code is more concise, exception information is more complete, and it is the best practice for Java resource management.
Other Extensions
Java 9 New Features