Java try-with-resources 语句
try-with-resources 是 Java 7 引入的一种简洁的资源管理方式,适用于需要在使用后自动关闭的资源(如文件、数据库连接、网络连接等)。
try-with-resources 能够很容易地关闭在 try-catch 语句块中使用的资源,所谓的资源(resource)是指在程序完成后,必须关闭的对象。
try-with-resources 语句确保了每个资源在语句结束时关闭。
所有实现了 java.lang.AutoCloseable 接口(其中,它包括实现了 java.io.Closeable 的所有对象),可以使用作为资源。
优势:
- 简化代码:省去手动关闭资源的代码,逻辑更清晰。
- 减少错误:自动处理资源关闭,避免忘记关闭资源或处理
finally块中出现的异常。 - 提升性能:减少资源泄露,节约系统资源。
执行流程
理解 try-with-resources 的核心在于掌握资源的生命周期,以及异常发生时的控制流走向。
基本语法
try-with-resources 语法如下:
try (ResourceType resource = new ResourceType()) {
// 使用资源
} catch (ExceptionType e) {
// 处理异常
}
在 try 块中声明的资源会在代码执行完毕后自动关闭,甚至在发生异常时也会安全关闭。
多资源管理(按声明逆序关闭):
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();
}
关闭顺序:
rs → stmt → conn(声明顺序的逆序)
关闭顺序:多个资源按声明顺序的 逆序 关闭,即后声明的资源先被关闭。这与栈式(LIFO)管理一致,确保依赖关系资源正确释放。
使用 AutoCloseable 接口
任何希望被 try-with-resources 管理的自定义类,只需实现 java.lang.AutoCloseable(或 java.io.Closeable)接口,并实现其 close() 方法。
实例
private final String url;
public DatabaseConnection(String url) {
this.url = url;
System.out.println("连接已建立: " + url);
}
public void query(String sql) {
System.out.println("执行查询: " + sql);
}
@Override
public void close() {
System.out.println("连接已关闭: " + url);
// 释放底层连接资源...
}
}
// 使用
try (DatabaseConnection db = new DatabaseConnection("jdbc:mysql://localhost/mydb")) {
db.query("SELECT * FROM users");
} catch (Exception e) {
e.printStackTrace();
}
输出:
连接已建立: jdbc:mysql://localhost/mydb 执行查询: SELECT * FROM users 连接已关闭: jdbc:mysql://localhost/mydb
异常处理与抑制异常
当 try 块中的业务逻辑 和 close() 同时抛出异常时,try-with-resources 采用特殊策略:业务异常作为主异常向上传播,close() 产生的异常被抑制(Suppressed)并附加在主异常上,可通过 getSuppressed() 获取。
实例
res.doSomething(); // 抛出 Exception A(业务异常)
} catch (Exception e) {
System.out.println("主异常: " + e.getMessage());
for (Throwable s : e.getSuppressed()) { // 获取 Exception B
System.out.println("抑制异常: " + s.getMessage());
}
}
输出:
主异常: Exception in doSomething 抑制异常: Exception in close
注意:传统 try-finally 中,finally 块的异常会覆盖业务异常,导致原始错误丢失。try-with-resources 通过抑制异常机制解决了这一经典陷阱。
Java 9 增强:复用外部变量
Java 9 之前,try-with-resources 要求资源必须在 try() 中重新声明。
Java 9 放开了这一限制:只要变量是 effectively final(事实上的常量),可直接在 try() 中引用,无需重复声明。
Java 7 / 8 — 必须重新声明
try (BufferedReader br1 = br) { // ← 必须声明新变量 br1
System.out.println(br1.readLine());
}
Java 9+ — 直接复用
try (br) { // ← 直接使用 br,无需重声明
System.out.println(br.readLine());
}
effectively final:变量在初始化之后未再被赋值,编译器会自动视其为 final。不需要显式写 final 关键字。
与 try-finally 对比
| 维度 | try-finally | try-with-resources |
|---|---|---|
| 代码量 | 多——需手动调用 close() | 少——自动关闭 |
| 遗漏 close 风险 | 高——人为疏忽易造成资源泄露 | 零——编译器保证 |
| 多资源嵌套 | 嵌套层层,可读性差 | 分号分隔,扁平清晰 |
| 异常处理 | finally 异常覆盖业务异常 | 抑制异常机制,信息完整保留 |
| 适用范围 | 任何清理逻辑 | 实现 AutoCloseable 的资源 |
try-finally 写法(冗长且易出错)
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) { // 还需判空
try { br.close(); } // close 本身也可能抛异常
catch (IOException e) { e.printStackTrace(); }
}
}
try-with-resources 写法(简洁安全)
String line;
while ((line = br.readLine()) != null) System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
常见使用场景
| 分类 | 常用类/接口 |
|---|---|
| 📁 文件 I/O | FileInputStream、FileOutputStream、BufferedReader、BufferedWriter、FileChannel |
| 🗄 数据库 | Connection、PreparedStatement、Statement、ResultSet、EntityManager |
| 🌐 网络通信 | Socket、ServerSocket、HttpURLConnection、InputStream、OutputStream |
在处理任何需要显式关闭的资源时,应优先使用 try-with-resources 而非 try-finally。它由编译器保证资源必然被关闭,代码更简洁,异常信息更完整,是 Java 资源管理的最佳实践。

Java 9 新特性