try-with-resources 的原理是什么?异常抑制如何处理?
结论先行:try-with-resources 是 JDK 7 引入的语法糖:声明在 try 括号中的资源(实现 AutoCloseable)在块结束时按声明逆序自动 close;若 close 抛异常且主逻辑也抛了异常,close 的异常会被追加为抑制异常(suppressed),绝不覆盖主异常。它替代了 finally + close 的样板代码,是资源管理的推荐写法。
关键规则
| 规则 | 说明 |
|---|---|
| 资源类型 | 必须实现 AutoCloseable(Closeable 是其子接口) |
| 关闭顺序 | 后声明的先关闭(逆序) |
| 主异常优先 | 块内异常 + close 异常同时出现时,close 异常被抑制 |
| 读取抑制异常 | Throwable.getSuppressed() 可取回被抑制的异常 |
| 多资源写法 | 括号内用分号声明多个,无需嵌套 |
import java.io.*;
public class TwrDemo {
static void copy(String src, String dst) throws IOException {
// 两个资源自动关闭,且 out 先于 in 关闭
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[1024];
int n;
while ((n = in.read(buf)) != -1) {
out.write(buf, 0, n);
}
}
}
public static void main(String[] args) throws Exception {
try (AutoCloseable a = () -> { throw new RuntimeException("close失败"); }) {
throw new IllegalStateException("主异常");
} catch (Exception e) {
System.out.println("主异常: " + e);
for (Throwable s : e.getSuppressed()) { // 查看被抑制的异常
System.out.println("被抑制: " + s);
}
}
}
}
常见追问 / 记忆点
- 记忆点:资源要 AutoCloseable、关闭按逆序、close 异常让位给主异常成为 suppressed。
- 追问:编译后 try-with-resources 会被展开成 try/finally,并用 addSuppressed 挂载 close 异常。
- 追问:不止流能关——Connection/Statement、锁等实现 AutoCloseable 的对象都适用;JDK 9 起 final 或等效 final 的变量也可作为资源。