社交媒体

try-with-resources 自动关资源

try-with-resources 自动关资源
title: 7 行换 3 行:Java 关资源的终极优雅写法
slug: java-30
cover: images/30-资源关闭三种姿势对比图.png
summary: 上篇说"用完必须 close",但你实际写起来是这样的:
tags:
  - Java
  - Java基础
  - try-with-resources
categories:
  - Java 入门基础系列

钩子:上篇欠的债,今天还

上篇说"用完必须 close",但你实际写起来是这样的:

FileWriter fw = null;
try {
    fw = new FileWriter("文件.txt");
    fw.write("内容");
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fw != null) {
        try {
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7 行干活的代码,配了 10 行关资源的代码。判空、嵌套 try、close 还会抛异常……写一次就明白什么叫"仪式感过重"。

有没有可能 Java 自己把这事办了?有,而且 2011 年(Java 7)就有了:try-with-resources。

核心:把资源塞进 try 的括号里

try (FileWriter writer = new FileWriter("文件.txt")) {
    writer.write("内容");
} catch (IOException e) {
    e.printStackTrace();
}
// 走到这里,writer 已经被自动 close 了

3 行干活的代码,0 行关资源。

规矩一句话:凡是"用完必须关"的资源,都放进 try 后面的括号里,Java 保证在 try 块结束时帮你 close——哪怕中途抛了异常。

它的底层依据是 AutoCloseable 接口:任何实现了这个接口的类,都能享受自动关闭。你自己的类也行:

class MyResource implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("我被自动关闭了");
    }
}
// try (MyResource res = new MyResource()) { ... }  ← 离开 try 自动调 close()

30-资源关闭三种姿势对比图.png

正题:两个隐藏细节

细节 1:多个资源,关闭顺序是"后开先关"。

try (BufferedReader br = new BufferedReader(new FileReader("a.txt"));
     BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"))) {
    // 干活
}   // 先关 bw,再关 br

像摞盘子:后放上去的先拿下来。这个顺序也是资源之间的依赖顺序——被包装的内层流往往依赖外层的。

细节 2:括号里声明的对象,出了 try 就不可见。

作用域仅限 try 块内。要在括号外面用,就在外面建好变量传进来。

还有一个冷知识:try-with-resources 后面照样可以接 catch 和 finally,而且异常不会互相"顶掉"——try 里抛的真异常永远优先于 close 抛的,不像手写 finally 会把异常吞了(第 27 篇讲过 finally 吞 return,同理更危险)。

速查表

对比项 不关 finally 手动关 try-with-resources
数据安全 ❌ 可能没落盘 ✅ ✅
代码量 — 7+10 行 3 行
异常处理 — close 的异常可能顶掉真异常 真异常优先
适用前提 — 任何资源 资源实现 AutoCloseable
结论 禁止 老代码会见到 无脑选它

本文示例代码均已本地实测通过,可直接运行。
对应文件:TryWithResourcesDemo.java


橙码酱,分享更有用的技术知识,助你成为更优秀的开发者。