The try-with-resources statement is a concise resource management mechanism introduced in Java 7, designed 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 blocks. A "resource" is an object that must be closed after the program is finished with it.
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 that implement java.io.Closeable) can be used as resources.
Advantages:
- Simplify Code: Eliminates the need for manual resource closing code, making the logic clearer.
- Reduce Errors: Automatically handles resource closure, avoiding forgotten closures or exceptions in
finallyblocks. - Improve Performance: Reduces resource leaks, saving system resources.
Execution Flow
Understanding the core of try-with-resources lies in grasping the lifecycle of resources and the control flow when an exception occurs.
Basic Syntax
The syntax for try-with-resources is as follows:
try (ResourceType resource = new ResourceType()) {
// Use the resource
} catch (ExceptionType e) {
// Handle exception
}
Resources declared in the try block are automatically closed after the code execution is complete, even if an exception occurs.
Managing multiple resources (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();
}
Closing order:
rs β stmt β conn (reverse order of declaration)
Closing Order: Multiple resources are closed in reverse order of their declaration, meaning the resource declared last is closed first. This aligns with stack (LIFO) management, ensuring dependent resources are released correctly.
Using the AutoCloseable Interface
Any custom class that wishes 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
public class DatabaseConnection implements AutoCloseable {
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:
Connection established: jdbc:mysql://localhost/mydb
Executing query: SELECT * FROM users
Connection closed: jdbc:mysql://localhost/mydb
Exception Handling and Suppressed Exceptions
When both the business logic in the try block and the close() method throw exceptions, try-with-resources employs a special strategy: the business exception is propagated as the primary exception, while the exception from close() is suppressed and attached to the primary exception. It can be retrieved via getSuppressed().
Example
try (ResourceWithException res = new ResourceWithException()) {
res.doSomething(); // Throws Exception A (business exception)
} catch (Exception e) {
System.out.println("Primary exception: " + e.getMessage());
for (Throwable s : e.getSuppressed()) { // Get Exception B
System.out.println("Suppressed exception: " + s.getMessage());
}
}
Output:
Primary exception: Exception in doSomething
Suppressed exception: Exception in close
Note: In traditional try-finally, the exception from the finally block can override 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 within the try() block.
Java 9 relaxed this restriction: as long as the variable is effectively final (a de facto constant), it can be directly referenced in the try() block without redeclaration.
Java 7 / 8 β Must Redeclare
BufferedReader br = new BufferedReader(new StringReader("hello"));
try (BufferedReader br1 = br) { // β Must declare new variable br1
System.out.println(br1.readLine());
}
Java 9+ β Direct Reuse
BufferedReader br = new BufferedReader(new StringReader("hello"));
try (br) { // β Use br directly, no redeclaration needed
System.out.println(br.readLine());
}
Effectively final: A variable that is not reassigned after initialization is automatically treated as final by the compiler. There is no need to explicitly write the final keyword.
Comparison with try-finally
| Dimension | try-finally | try-with-resources |
|---|---|---|
| Code Volume | More β requires manual close() calls |
Less β automatic closure |
Risk of Omitting close() |
High β human oversight can cause resource leaks | Zero β guaranteed by the compiler |
| Multiple Resource Nesting | Nested layers, poor readability | Semicolon-separated, flat and clear |
| Exception Handling | Finally block exception overrides business exception | Suppressed exception mechanism, information fully preserved |
| Scope of Application | Any cleanup logic | Resources implementing AutoCloseable |
try-finally Approach (Verbose and Error-Prone)
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) { // Still need null check
try {
br.close(); // close() itself might throw an exception
} catch (IOException e) {
e.printStackTrace();
}
}
}
try-with-resources Approach (Concise and Safe)
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();
}
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 handling any resource that requires explicit closure, try-with-resources should be preferred over try-finally. It is guaranteed by the compiler to close resources, results in more concise code, and preserves more complete exception information, making it the best practice for resource management in Java.
YouTip