try-with-resources 直接替代传统 try-finally 的手动关闭职责,资源须实现 AutoCloseable 接口,JVM 保证按声明逆序自动调用 close();Java 9+ 支持 effectively final 变量直接引用;仅 native 内存、自定义锁等非 AutoCloseable 场景才需 finally。

try-with-resources 直接替代了传统 try-finally 中“手动关闭资源”的全部职责,只要资源类型实现 AutoCloseable 接口,就无需再写 finally 块来关流、关连接或关扫描器。
核心替代逻辑
传统 try-finally 的本质是:确保无论是否异常,都执行 close()。而 try-with-resources 在字节码层面自动插入等效逻辑——JVM 保证在 try 块退出(正常结束或抛异常)后,按声明逆序调用每个资源的 close() 方法。这不再是“建议写法”,而是由语言机制强制保障的行为。
- 资源必须实现 AutoCloseable(如 FileInputStream、Connection、Scanner、BufferedReader 等),否则编译不通过
- 多个资源用分号隔开,后声明的先关闭,天然适配依赖关系(例如 BufferedInputStream 应在底层 FileInputStream 之后关闭)
- 即使 close() 抛异常,也不会覆盖主异常;它会被作为被抑制异常(suppressed exception)附加到主异常上,可通过
e.getSuppressed()查看
典型代码对比
传统写法(冗长、易漏、异常易丢失):
FileInputStream in = null;
try {
in = new FileInputStream("data.txt");
// 读取操作
} catch (IOException e) {
log.error("读取失败", e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ignored) {}
}
}
替换成 try-with-resources 后(简洁、安全、异常完整):
立即学习“Java免费学习笔记(深入)”;
try (FileInputStream in = new FileInputStream("data.txt")) {
// 读取操作,无需关心关闭
} catch (IOException e) {
log.error("读取失败", e);
}
Java 9 起支持更灵活的写法
不再强制要求资源必须在 try 括号内 new 出来。只要变量是 effectively final(未被重新赋值),就可以直接引用:
final InputStream in = new FileInputStream("data.txt");
try (in) { // Java 9+ 允许这样写
in.read();
} // 自动关闭 in
这种写法特别适合需要预处理资源(如包装成 BufferedInputStream)、或资源来自方法参数/配置注入等场景。
哪些情况仍需 finally?
仅限两类非 AutoCloseable 场景,且 finally 中绝不碰已由 try-with-resources 管理的资源:
- 清理 native 内存(如 Unsafe.allocateMemory)、自定义锁状态、ThreadLocal 变量等无法自动管理的对象
- 重置共享状态,例如事务中执行
connection.rollback()(注意:connection 本身仍用 try-with-resources 关闭)
重复关闭同一资源会导致 IllegalStateException、NPE 或干扰异常抑制机制,属于明确禁止行为。


















