Java try-with-resources
try-with-resources 如何在异常路径上可靠关闭资源,以及抑制异常(suppressed)语义。
#type / concept
#status / growing
#tech / dev
#resource / java
[!info] 关联笔记
Java try-with-resources
这个概念为什么出现
文件、套接字、数据库连接都必须关闭。手工 try/finally 易漏、顺序错、二次异常掩盖主异常。try-with-resources 把“用完即关”做成语法,并保留抑制异常信息。
[!abstract] 一句话理解 在
try (...)中声明的AutoCloseable资源会在块结束时按逆序自动close;主异常上可挂载关闭阶段的 suppressed 异常。
最小可运行示例
场景:导出服务写临时报表文件
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
public class ReportExport {
// export:写一行报表。
// 教学点:BufferedWriter 在 try-with-resources 中自动关闭(会 flush)。
static void export(Path path, String line) throws IOException {
try (BufferedWriter w = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
w.write(line);
w.newLine();
} // 此处自动 close
}
public static void main(String[] args) throws Exception {
Path p = Files.createTempFile("report-", ".txt");
export(p, "order=1,ok");
System.out.println(Files.readString(p).trim());
Files.deleteIfExists(p);
}
}
建议运行:
javac ReportExport.java && java ReportExport
期望输出:
order=1,ok
结合场景再看三个关注点
- 资源声明在 try 括号内才自动管理。
- 多个资源逆序关闭(后开先关)。
- 关闭失败不会默默丢掉主异常(suppressed)。
核心概念与准确模型
1. 语法
try (Resource r = open()) {
use(r);
}
2. 等价直觉
编译器生成 finally 风格关闭,并处理异常抑制。
3. 抑制异常
- 主异常在 body
- close 抛出的额外异常进入
getSuppressed()
4. 生效条件
- 资源实现
AutoCloseable/Closeable - 变量有效 final
边界情况与反直觉行为
- 资源赋值 null 不会 close。
- 在 body 里手动提前 close 要避免双重语义混乱。
- 依赖关闭顺序的资源要按正确顺序声明。
常见误区
[!warning] 常见误区:打开资源在 try 外再在 finally close 新代码优先 try-with-resources,减少遗漏。
工程实践
- IO/JDBC/HTTP 客户端响应体一律 TWR。
- 自定义资源实现
AutoCloseable。 - 测试异常路径是否仍关闭(可用计数包装)。
- 日志打印 suppressed。
本节总结
- 自动关闭 + 异常更安全
- 逆序 close + suppressed
- IO/JDBC 标配
自测题
- 两个资源关闭顺序?
- 为什么还需要
getSuppressed?
参考答案
- 与声明相反:后获取的先关闭。
- 关闭阶段异常不能覆盖主异常,但必须可观测。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The try-with-resources Statement | 教程 | 语法与 suppressed |
| AutoCloseable | API | 关闭契约 |