try-with-resources 原理
面试官问:"try-with-resources 是什么?和 try-finally 相比有什么优势?"
候选人小马答:"资源会自动关闭,不用手动写 finally。"
面试官追问:"如果 try 和 close 都抛异常,返回哪个?"
小马说:"close 的异常?"
面试官又问:"如果多个资源都抛异常呢?"
小马彻底不知道了。
【面试官心理】 这道题问的是候选人有没有深入理解过 Java 的 suppress 异常机制。这是 JDK 7 引入的重要特性,但 90% 的候选人只知道"会自动关闭",不知道异常处理的细节。
一、基本原理 🔴
1.1 AutoCloseable 接口
1.2 自动关闭机制
💡
finally 中如果 close 也抛异常,JDK 7+ 会用 addSuppressed() 把 close 的异常附加到 primary 异常上,而不是覆盖。
二、Suppress 异常链 🔴
2.1 单个资源的异常场景
2.2 多个资源都抛异常
顺序:
in.read()抛异常 → 记录为 primaryin.close()抛异常 → 作为suppress附加out.close()抛异常 → 作为suppress附加
⚠️
try-with-resources 的异常抑制顺序取决于资源声明的反向顺序(先声明的后 close)。这是 JDK 7 就设计好的行为,和 try-finally 中手动 close 的顺序不同,容易搞混。
三、多资源声明顺序 🔴
四、隐藏的陷阱 🔴
4.1 资源初始化异常
答案:能。编译器生成的字节码会确保每个成功初始化的资源都被正确关闭。
4.2 close 方法的性能要求
4.3 变量类型必须实现 AutoCloseable
五、自定义资源的最佳实践 🔴
:::tip 💡
自定义资源的 close() 方法建议:
- 幂等:多次 close 不抛异常
- 不抛受检异常:因为 close 通常在 try-with-resources 末尾调用,抛出的异常可能被 suppress
- 设置状态标志:方便后续操作做校验 :::
六、追问升级
面试官:"JDK 9 之后 try-with-resources 有什么改进?"
JDK 9 引入了" Effectively Final"变量的支持:
【面试官心理】 能说出 JDK 9 改进的候选人,说明有关注 Java 版本演进的习惯。这种细节是 P6/P7 的加分点。