try-with-resources不替代catch,而是与catch协同:前者自动关闭实现autocloseable的资源并处理关闭异常(抑制机制),后者捕获业务异常;多资源分号隔开、逆序关闭,关闭异常通过getsuppressed获取,无需手动finally。

try-with-resources 本身不替代 catch,而是和 catch 协同工作:资源自动关闭由 try-with-resources 负责,异常处理逻辑由 catch(和 finally)负责。关键在于理解它们的职责边界和执行顺序。
资源声明放在 try 括号里,异常捕获写在后面
语法结构固定:先写 try (声明并初始化资源),再跟一个或多个 catch 块,可选 finally。资源会在 try 块结束(无论正常还是异常退出)时自动关闭,且关闭过程中的异常会被正确抑制或抛出。
- 资源必须实现 AutoCloseable 接口(如 FileInputStream、BufferedReader、Connection 等)
- 多个资源用分号隔开,关闭顺序与声明顺序相反(后声明的先关闭)
- catch 块捕获的是 try 块中业务代码抛出的异常,不是关闭时的异常(除非没有业务异常)
关闭异常会被“抑制”,但不会丢弃
如果 try 块中已抛出异常(比如读文件失败),而资源关闭时又发生异常(比如 close() 失败),后者不会覆盖前者,而是作为 suppressed exception 附加到主异常上。
- 可通过
exception.getSuppressed()获取被抑制的异常数组 - 调试时 IDE 或日志通常会一并打印主异常和 suppressed 异常
- 不需要手动写 finally 关闭资源,否则可能重复关闭或干扰 suppress 机制
需要分别处理业务异常和关闭异常?用多重 catch + 显式关闭(慎用)
绝大多数场景下,让 try-with-resources 自动管理即可。只有极少数情况需干预关闭行为,例如:
- 想对某个资源的关闭失败做特殊日志或补偿(如记录关闭失败但继续执行)
- 资源 close() 可能抛出受检异常,而你不想向上抛出,需在 close 后立即捕获
此时可把资源声明移出 try 括号,改用传统 try-catch-finally,并在 finally 中手动 close —— 但这会失去 try-with-resources 的简洁性和抑制机制,不推荐作为默认方案。
常见错误避免
-
不要在 try-with-resources 的括号里调用方法返回资源并同时赋值给变量:如
try (FileInputStream fis = new FileInputStream("a.txt").getChannel().open())是错的,因为中间对象无法被自动管理 - 不要在 try 块内重新赋值资源变量:会导致原资源未被关闭(JDK 不报错但逻辑失效)
- catch 块中不要依赖已关闭的资源:比如在 catch 里再次调用 fis.read(),会抛出 IOException
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











