Java 7 try-with-resources要求资源必须实现AutoCloseable接口,否则编译报错;多个资源按声明逆序关闭;关闭异常会被主异常抑制并通过getSuppressed()获取。

Java 7 try-with-resources 要求资源必须实现 AutoCloseable
不是所有“能关”的类都能进 try-with-resources,只有声明了 AutoCloseable(或其子接口 Closeable)的类型才被允许。比如 FileInputStream、BufferedReader、Connection 都可以;但你自己写的普通工具类,哪怕有 close() 方法,只要没实现 AutoCloseable,编译器就直接报错:cannot be auto-closed。
实操建议:
- 自定义资源类时,别只加个
close()方法,一定要implements AutoCloseable,且重写close()抛出Exception(不能是更具体的异常,除非你用throws显式声明) -
Closeable是AutoCloseable的子接口,它强制close()抛IOException,所以如果你的资源只可能抛 IO 异常,用Closeable更语义准确 - 注意 JDK 7 新增的
AutoCloseable是为了泛化关闭语义——它不局限于 IO,比如 JDBC 的ResultSet、Statement也实现了它,哪怕它们不涉及流
多个资源怎么写?分号分隔,顺序决定关闭顺序
try-with-resources 括号里可以声明多个资源,用分号隔开。它们按**声明顺序的逆序**关闭:先声明的后关,后声明的先关。这点和嵌套 try 很像,但不用手动写嵌套。
常见错误现象:
立即学习“Java免费学习笔记(深入)”;
- 把依赖关系搞反了:比如先声明
Connection再声明PreparedStatement,这是对的;但如果反过来,PreparedStatement可能在Connection关闭后还试图操作,运行时报SQLException: connection closed - 混用变量声明和赋值:不能在括号里写
MyResource r = new MyResource();这种带等号的完整语句,只能是“类型 变量名 = 表达式”形式,且必须是可关闭资源
示例(正确):
try (Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM user");
ResultSet rs = ps.executeQuery()) {
// 处理结果
}异常抑制(suppressed exception)是怎么回事?
当 try 块抛异常,且资源关闭时也抛异常,Java 7+ 会把关闭异常“压制”到主异常上,而不是覆盖它。主异常的 getSuppressed() 方法能拿到被压制的异常列表。
为什么这样做?因为业务逻辑出错(比如 SQL 语法错)比资源关不掉(比如网络抖动导致连接池 close 超时)更关键,不能让后者掩盖前者。
实操建议:
- 不要在
close()里吞掉异常——即使你写了try-catch,也要至少打日志,否则压制后完全看不到关闭失败 - 调试时如果发现主异常堆栈里没看到预期的关闭问题,记得调
e.getSuppressed()看一眼 -
try-with-resources自动生成的 finally 块等效于:先执行 try 块,再按逆序调每个资源的close(),每次close()出异常都调addSuppressed()
Java 7 的 try-with-resources 不支持 catch 或 finally 子句中的资源管理
它只管括号里声明的资源。如果你在 try 块里又 new 了一个 BufferedWriter,但没把它放进括号,那它不会被自动关闭——哪怕你写了 finally { bw.close(); },也不算“自动”,而且容易漏 null 判断或重复 close。
使用场景提醒:
- 资源生命周期必须和 try 块完全一致:即“打开 → 使用 → 关闭”都在这个块内完成。跨方法传递资源对象后还想靠它自动关?不行
- 不支持动态资源列表:不能写
for (Resource r : list) try (r) { ... },每个r必须单独声明在自己的 try 括号里 - JDK 9 开始支持“有效 final”的变量引用,比如
final Resource r = new Resource(); try (r) { ... },但 Java 7 不行,必须在括号里直接 new 或调工厂方法
最常被忽略的一点:很多人以为只要用了 try-with-resources 就高枕无忧,其实它只解决“语法层面的关闭时机”,不解决“业务逻辑是否真的用完了资源”。比如 ResultSet 没遍历完就退出 try 块,Connection 还是会被关,但下层连接可能没真正释放——这得看具体数据源实现,不是语法能兜住的。










