← [ BACK_TO_NOTES ]

Java try-with-resources

try-with-resources 如何在异常路径上可靠关闭资源,以及抑制异常(suppressed)语义。

#concept #growing #dev #java

[!info] related notes

Java try-with-resources

这个概念为什么出现

文件、套接字、数据库连接都必须关闭。手工 try/finally 易漏、顺序错、二次异常掩盖主异常。try-with-resources 把“用完即关”做成语法,并保留抑制异常信息。

[!abstract] 一句话理解 在 try (...) 中声明的 AutoCloseable 资源会在块结束时按逆序自动 close;主异常上可挂载关闭阶段的 suppressed 异常。

[!note] 边界 AutoCloseable 接口、资源所有权与生命周期纪律以 资源生命周期与 AutoCloseable 为 canonical;本文只解释 try-with-resources 这套语法机制及 suppressed exception 语义。

最小可运行示例

场景:导出服务写临时报表文件

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

public class ReportExport {
    // export:写一行报表。
    // 教学点:BufferedWriter 在 try-with-resources 中自动关闭(会 flush)。
    static void export(Path path, String line) throws IOException {
        try (BufferedWriter w = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
            w.write(line);
            w.newLine();
        } // 此处自动 close
    }

    public static void main(String[] args) throws Exception {
        Path p = Files.createTempFile("report-", ".txt");
        try {
            export(p, "order=1,ok");
            System.out.println(Files.readString(p).trim());
        } finally {
            Files.deleteIfExists(p); // 文件句柄关闭与删除临时文件是两件事
        }
    }
}

建议运行:

javac ReportExport.java && java ReportExport

期望输出:

order=1,ok

结合场景再看三个关注点

  1. 资源需列在 try 括号内才自动管理;Java 9+ 也允许 try(existingResource),引用已声明的 final/effectively final 变量。\
  2. 多个资源逆序关闭(后开先关)。
  3. 关闭失败不会默默丢掉主异常(suppressed)。

核心概念与准确模型

1. 语法

try (Resource r = open()) {
  use(r);
}

2. 等价直觉

编译器生成 finally 风格关闭,并处理异常抑制。

3. 抑制异常

  • body 抛异常时,它通常作为主异常;逆序 close 的异常追加到 getSuppressed()。
  • body 正常完成但 close 抛异常时,第一个关闭异常成为主异常,其余关闭异常被抑制。
  • 资源按从左到右初始化;后一个初始化失败时,先前已成功初始化的资源仍会逆序关闭,初始化异常作为主异常。\

4. 生效条件

  • 资源实现 AutoCloseable/Closeable
  • try 内声明的资源变量隐式 final;Java 9+ 引用外部变量时要求 final 或 effectively final。\

边界情况与反直觉行为

  1. 资源初始化结果为 null 时跳过 close;不是允许在 body 内重赋资源变量。\
  2. 在 body 里手动提前 close 要避免双重语义混乱。
  3. 依赖关闭顺序的资源要按正确顺序声明。
  4. 某个构造器内部获取资源后抛错,尚未完成构造的对象不会被 TWR 自动关闭,构造器要自行回滚。
  5. TWR 不是 JVM 被强制终止、System.exit 或无限阻塞时的清理保证;close 也不自动意味着删除文件或数据落盘。\

常见误区

[!warning] 常见误区:打开资源在 try 外再在 finally close 新代码优先 try-with-resources,减少遗漏。

工程实践

  1. 对由当前作用域拥有且实现 AutoCloseable 的 IO/JDBC/HTTP 资源使用 TWR;不要提前关闭借用资源或返回给调用方的流。\
  2. 自定义资源实现 AutoCloseable。
  3. 测试异常路径是否仍关闭(可用计数包装)。
  4. 日志打印 suppressed。

本节总结

  • 自动关闭 + 异常更安全
  • 逆序 close + suppressed
  • IO/JDBC 标配

自测题

  1. 两个资源关闭顺序?
  2. 为什么还需要 getSuppressed?
参考答案
  1. 与声明相反:后获取的先关闭。
  2. 关闭阶段异常不能覆盖主异常,但必须可观测。

延伸阅读与资料来源

资料类型支撑内容
The try-with-resources Statement教程语法与 suppressed
AutoCloseableAPI关闭契约
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本