try-with-resources 是编译期语法糖,javac 将其翻译为显式 try-finally 结构,插入 close() 调用、null 检查及 addsuppressed 异常抑制逻辑,不依赖 jvm 运行时。

编译器生成 finally 块并确保 close() 执行
`try-with-resources` 中声明的每个资源(实现 `AutoCloseable`)会被编译器转换为一个隐式声明的 final 局部变量,并在 `try` 正常退出或异常抛出后,**强制插入 `finally` 块执行其 `close()` 方法**。该 `finally` 块不是“自动添加”的语法糖,而是编译器输出的真实字节码指令(如 `jsr`/`ret` 在旧版或更常见的是结构化 `goto` + 异常表条目),与手写的 `try-finally` 行为一致。
- 资源变量在 `try` 入口处初始化,作用域被限制在 `try` 块内
- 无论 `try` 块是否抛异常、是否提前 return,编译器都会生成对应 `finally` 分支,调用 `close()`
- 若资源为 `null`(如构造失败),编译器会生成空检查,跳过 `close()` 调用(避免 NPE)
异常抑制(addSuppressed)由编译器显式编码
当 `try` 块抛出异常 A,且 `finally` 中 `close()` 又抛出异常 B 时,编译器生成的字节码会:
- 先保存 `try` 抛出的主异常 A 到局部变量
- 在 `finally` 中调用 `close()`;若抛出异常 B,则用 `A.addSuppressed(B)` 将 B 添加为被抑制异常
- 最终重新抛出 A(而非 B),B 成为其 `getSuppressed()` 返回数组中的一项
- 这一过程完全由编译器生成 `invokevirtual Throwable.addSuppressed` 指令实现,无魔法或反射
多资源按逆序关闭,抑制逻辑逐层嵌套
多个资源(如 `try (R1 r1 = ...; R2 r2 = ...)`)会被编译为嵌套的 `try-finally` 结构:
- 最外层 `try` 包裹全部业务代码
- 每层 `finally` 关闭一个资源,顺序与声明相反(r2 先于 r1 关闭)
- 每一层都做自己的异常捕获 → `addSuppressed` → 重抛,因此异常抑制是链式累积的
- 字节码中能看到多个 `astore`/`aload` 配合 `ifnull`、`invokevirtual close` 和 `addSuppressed` 的重复模式
你可以用 `javap -c` 查看编译后的字节码,会清晰看到 `finally` 对应的代码块、`athrow` 指令前的 `addSuppressed` 调用,以及资源变量的栈操作痕迹。它本质是语法糖,但实现扎实、透明、可预测。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











