try-with-resources中资源按声明逆序关闭:后声明的先关,先声明的后关;资源须独立声明不可复用;close异常被抑制并附加到主异常;推荐分行声明以提升可读性与规范性。

在 try-with-resources 中声明多个 AutoCloseable 资源时,**变量声明顺序直接决定关闭顺序**:后声明的先关闭,先声明的后关闭,即严格按“逆序”释放。这不是嵌套结构,而是编译器生成的线性资源管理逻辑——它不等价于手动嵌套 try 语句,但效果上能自然满足依赖关系(比如包装流必须晚于被包装流创建、早于其关闭)。
资源声明必须独立、不可复用
每个资源需单独声明并初始化,不能用已有变量赋值或重复使用同一变量名。例如:
✘ 错误写法:
FileInputStream fis = new FileInputStream("a.txt");<br>
try (fis; BufferedInputStream bis = new BufferedInputStream(fis)) { ... }
这会编译失败——括号内只能是声明语句,不是表达式或变量引用。
✔ 正确写法:
try (FileInputStream fis = new FileInputStream("a.txt");<br>
BufferedInputStream bis = new BufferedInputStream(fis)) { ... }
关闭顺序严格按声明逆序,不是按使用逻辑
即使 bis 依赖 fis,JVM 仍先调用 bis.close(),再调用 fis.close()。这是设计使然,也是安全前提——包装类 close() 通常会触发底层流的 flush 和基础关闭,而自身不持有独占锁或句柄;若反过来先关 fis,bis 再 close 就可能抛出 IOException 或静默失效。
- 声明顺序:A → B → C
- 实际关闭顺序:C → B → A
- 适合场景:外层装饰器(如 BufferedReader)、中间缓冲器(BufferedInputStream)、底层通道(FileInputStream/Socket)
异常处理中关闭失败会被抑制,不影响主异常
如果 try 块已抛出异常(如 IOException),而某个资源 close() 又抛出另一个异常(如 SocketException),后者不会覆盖前者,而是作为 suppressed exception 附加到主异常对象上。可通过 exception.getSuppressed() 获取。
这意味着你无需为每个 close() 单独捕获——机制已内置容错,但调试时要注意检查 suppressed 异常,它们常暴露连接未正常终止、磁盘满、远程服务异常断连等问题。
推荐写法:每行一个资源,提升可读与维护性
尤其当资源构造含参数或需要注释说明时,分行声明更清晰:
try (<br>
Connection conn = dataSource.getConnection();<br>
PreparedStatement ps = conn.prepareStatement(sql);<br>
ResultSet rs = ps.executeQuery()<br>
) {<br>
// 执行业务逻辑<br>
}
此时关闭顺序是:rs → ps → conn,完全符合 JDBC 资源释放规范,也避免了手动 finally 中因遗漏或顺序错导致的 Statement 关闭失败进而阻塞 Connection 归还连接池的问题。










