系列前面验证过 try 主体和 close() 都抛异常时,close() 的异常会真实变成 suppressed。这次验证一个更常见的场景:try 主体压根没抛异常,只有 close() 出了问题,会发生什么。
上一篇:parallelStream() 真实用了几个线程:真实捕获到 main 线程也参与了计算
try 块内部正常执行完,没有任何异常;唯一的异常来自资源的 close() 方法。
CloseExceptionDemo.java static class Res implements AutoCloseable { final String name; Res(String name) { this.name = name; } @Override public void close() { throw new RuntimeException(name + " 关闭时真实抛出的异常"); } } try (Res a = new Res("A")) { System.out.println("try 块内部正常执行,没有抛任何异常"); } catch (Exception e) { ... }
try 块内部正常执行,没有抛任何异常 真实 catch 到的异常 = A 关闭时真实抛出的异常 这个异常真实是 close() 直接抛出的那个,不是包在 suppressed 里的 真实 suppressed 异常个数 = 0
真实结果很直接:try 主体没有任何异常,close() 抛出的这个异常没有"降级"成谁的附属品,而是真实、直接地成为了这次调用真正抛出的异常——调用方 catch 到的就是它本身,getSuppressed() 真实是空数组。
这部分是系列前面已经验证过的机制,这里作为对照重新确认。
真实 catch 到的异常 = try 主体真实抛出的异常 真实 suppressed 异常个数 = 1 suppressed: A 关闭时真实抛出的异常
两组真实结果对比能看出完整的规律:try-with-resources 的异常处理机制真实只有"一个主异常"这个概念——谁先出现真实的异常,谁就优先成为主异常;后出现的异常(不管是另一个资源的 close(),还是同一个资源的 close())如果这时候已经有主异常了,就会被真实、完整地记录进 suppressed 数组,不会丢失,但也不会喧宾夺主。
try 主体正常,但两个资源的 close() 都抛异常——真实哪一个会变成最终抛出的主异常。
try 块内部正常执行 真实 catch 到的异常 = B 关闭时真实抛出的异常(应该是后关闭的那个,因为是逆序关闭,B 先关) 真实 suppressed 异常个数 = 1 suppressed: A 关闭时真实抛出的异常
每一行都是真实运行这段代码得到的异常和 suppressed 结果。