关键在于按依赖关系反向声明资源:被包装的底层资源先声明,包装它的上层资源后声明。这样关闭时上层先关、底层后关,符合流式封装的释放逻辑。

依赖关系决定声明顺序
比如 BufferedWriter 依赖 FileWriter,就必须写成:
try (FileWriter fw = new FileWriter("a.txt"); BufferedWriter bw = new BufferedWriter(fw)) { ... }- 这样
bw后声明 → 先关闭,fw先声明 → 后关闭 -
bw.close()会刷新缓冲并调用fw.close(),而此时fw还有效
多个独立资源也需注意关闭时序
即使没有包装关系,如同时读写两个文件,也要考虑业务语义:
- 若写操作依赖读结果(如复制文件),建议先声明输入流、再声明输出流:
InputStream is; OutputStream os - 这样
os先关、is后关,确保写入完成后再释放源 - 反过来声明可能在写未完成时就提前关闭了输入源(取决于具体实现和异常路径)
构造失败时的自动清理很可靠
如果中间某个资源初始化失败(如第二个 new FileOutputStream() 抛出 FileNotFoundException),前面已创建的资源会立即按逆序关闭:
- 声明为
A a = new A(); B b = new B(); C c = new C() - 若
C构造失败,则B和A会依次关闭(B先于A) - 无需手动补救,编译器生成的嵌套
try-finally已保障这点
不推荐手动干预关闭流程
不要在 try 块里调用 close(),也不要在 finally 里重复关:
立即学习“Java免费学习笔记(深入)”;
- 手动调用可能导致重复关闭,部分实现会抛
IllegalStateException - 与 try-with-resources 的自动机制冲突,破坏逆序保证
- 若真有特殊释放逻辑,应封装进自定义
AutoCloseable的close()方法中


















