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()

正题:两个隐藏细节
细节 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
橙码酱,分享更有用的技术知识,助你成为更优秀的开发者。