try-with-resources不捕获异常,仅确保资源自动关闭;业务异常由后续catch块捕获,close异常被抑制并附加到主异常上,可通过getSuppressed()获取。

try-with-resources 本身不负责“捕获”异常,它只确保资源自动关闭;业务异常仍由标准的 catch 块捕获,方式和普通 try-catch 完全一致。
业务异常照常用 catch 捕获
你只需在 try-with-resources 后面写上对应的 catch,就能捕获 try 块内抛出的任何业务异常。比如:
- 文件读取失败 → 抛
IOException,被catch (IOException e)捕获 - 数据库查询出错 → 抛
SQLException,可用catch (SQLException e)单独处理 - 手动 throw 新异常(如参数校验失败)→ 会被最匹配的
catch捕获,和是否用 try-with-resources 无关
别让 close() 异常干扰业务异常的传播
如果业务代码抛了异常,同时资源 close() 也失败,JVM 默认会把 close() 异常“压制”(suppressed)到主异常上,而不是覆盖它。但这个机制生效的前提是:
- 业务异常必须真正向外抛出(不能在 catch 里吞掉或 return 中断)
- 不要在 try 块末尾写
return或额外throw,否则可能打断异常链 - 若需查看被压制的异常,调用
e.getSuppressed()即可
多资源场景下异常捕获逻辑不变
多个资源声明在括号中(如 try (A a = new A(); B b = new B())),关闭顺序是逆序,但异常捕获规则没变:
立即学习“Java免费学习笔记(深入)”;
- 只要 try 块中任意位置抛出业务异常,它就是主异常
- 后续资源 close 失败时,异常会依次被 addSuppressed 到主异常上
- 最终你 catch 到的仍是那个原始业务异常,只是多了可查的 suppressed 信息
常见错误:在 catch 里吃掉异常就等于丢掉现场
下面这种写法会让业务异常彻底消失,压制机制也失效:
-
catch (IOException e) { log.info("忽略"); }→ 主异常没抛出,close 异常直接往外扔,掩盖真实问题 -
catch (Exception e) { return null; }→ 异常被截断,调用方收不到任何提示 - 正确做法是:记录日志 + 重新抛出,或封装后抛出更明确的异常


















