Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

  • Java集合

  • Java并发

  • Java IO

    • Java IO概述
    • IO基础

    • 常用IO流

    • 文件与目录操作

    • Java NIO

    • 高级主题

    • 实践与性能优化

      • try-with-resources资源管理
        • 1. 为什么必须关闭资源
        • 2. 传统 finally 写法
        • 3. try-with-resources
        • 4. 多资源关闭顺序
        • 5. 异常抑制
        • 6. 包装流关闭
        • 7. 不应该关闭的资源
        • 专家实践清单
        • Tips 快问快答
        • 8. 总结
      • 大文件读写
      • 文本文件处理
      • IO性能优化
      • IO常见坑
    • 面试与设计题

    • IO实践速查

  • JVM

目录

try-with-resources资源管理

IO 资源通常对应操作系统资源,例如文件描述符、Socket 连接、缓冲区等。如果不及时关闭,可能导致文件无法删除、连接耗尽、进程打开文件数超限等线上问题。

# 1. 为什么必须关闭资源

Java 对象由 GC 管理,但底层 IO 资源不应该依赖 GC 间接释放。

例如 FileInputStream 背后可能持有文件描述符。如果大量文件流没有关闭,可能出现:

Too many open files

这是典型的资源泄漏问题。

# 2. 传统 finally 写法

早期代码常用 finally 关闭资源:

InputStream input = null;
try {
    input = new FileInputStream("data.txt");
    // read data
} finally {
    if (input != null) {
        input.close();
    }
}

如果有多个资源,代码会变得冗长,而且异常处理容易写错。

# 3. try-with-resources

Java 7 引入了 try-with-resources。

try (InputStream input = new FileInputStream("data.txt")) {
    // read data
}

只要资源实现了 AutoCloseable 或 Closeable,就可以放在 try 括号中,执行结束后自动关闭。

# 4. 多资源关闭顺序

try (InputStream input = new FileInputStream("source.txt");
     OutputStream output = new FileOutputStream("target.txt")) {
    input.transferTo(output);
}

多个资源会按照声明的反向顺序关闭。

先关闭 output
再关闭 input

这符合包装流的使用习惯:通常外层资源先关闭,底层资源后关闭。

# 5. 异常抑制

如果 try 块中发生异常,关闭资源时也发生异常,后者会作为 suppressed exception 附加到主异常上。

catch (IOException e) {
    for (Throwable suppressed : e.getSuppressed()) {
        suppressed.printStackTrace();
    }
}

这比传统 finally 更可靠,因为 finally 中的关闭异常可能覆盖原始异常。

# 6. 包装流关闭

通常只需要把最外层流放入 try。

try (BufferedReader reader = new BufferedReader(
        new InputStreamReader(new FileInputStream("data.txt"), StandardCharsets.UTF_8))) {
    // read
}

关闭 BufferedReader 会继续关闭 InputStreamReader 和 FileInputStream。

# 7. 不应该关闭的资源

并不是所有拿到的流都应该由当前方法关闭。例如:

  • Servlet 容器管理的 request.getInputStream()。
  • 框架传入的响应流。
  • 调用方要求继续使用的流。

谁创建资源,谁负责关闭,这是常见原则。方法如果接收外部传入的流,要在接口契约中明确是否关闭。

# 专家实践清单

检查项 建议 原因
资源创建 放在 try 资源声明中 自动关闭
关闭顺序 后创建先关闭 符合包装流依赖关系
异常保留 查看 suppressed 异常 避免关闭异常覆盖主异常
所有权 谁创建谁关闭 避免误关外部流
接口契约 明确是否关闭传入流 防止调用方误用

关闭链路:

try 块执行
  │
  ├─ 正常完成
  └─ 抛出业务异常
       ▼
自动按逆序 close
       ▼
保留主异常和 suppressed 异常

# Tips 快问快答

Q:try-with-resources 解决什么问题? A:确保实现 AutoCloseable 的资源在离开作用域时自动关闭。

Q:多个资源关闭顺序是什么? A:按声明的逆序关闭。

Q:关闭时也抛异常怎么办? A:主异常保留,关闭异常通常作为 suppressed 异常附加。

Q:所有资源都该在方法里关闭吗? A:不一定,只有方法创建并拥有的资源才应由方法关闭。

Q:为什么不能依赖 GC 关闭文件? A:GC 时机不确定,外部资源可能长期占用。

Q:包装流只关闭最外层可以吗? A:通常可以,关闭会向内传递。

Q:AutoCloseable 和 Closeable 有什么关系? A:Closeable 继承自 AutoCloseable,更偏 IO 资源。

Q:资源关闭最常见线上问题是什么? A:文件描述符或连接泄漏,最终导致打开文件过多或连接耗尽。

# 8. 总结

IO 代码中资源关闭是可靠性的底线。新代码应默认使用 try-with-resources,并明确资源所有权。不要依赖 GC,不要吞掉关闭异常,不要随意关闭不属于自己的流。

上次更新: 2026/06/25, 14:19:18
序列化安全与替代方案
大文件读写

← 序列化安全与替代方案 大文件读写→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式