Java try-with-resources Statement

Java 9 新特性Java 9 New Features

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 handlingfinallyexceptions 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.

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

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

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:

连接已建立: 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().

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

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()) {   // 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

BufferedReader br = new BufferedReader(new StringReader("hello"));
try (BufferedReader br1 = br) {    // ← Must declare a 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: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)

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) {               // 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)

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 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.

Java 9 新特性Java 9 New Features

Other Extensions