必须从外向内依次调用close(),因为外层装饰器持有内层流引用并在自身close()中委托关闭;若顺序错误,会导致资源泄漏、IOException或StreamClosedException。

关闭嵌套的 Decorator 流时,必须从外向内依次调用 close(),即先关闭最外层的装饰器(如 BufferedInputStream),再逐层向内关闭被装饰的流。这是 Java I/O 的标准实践,也是确保资源正确释放的关键。
为什么必须从外向内 close
Decorator 模式中,外层流持有对内层流的引用,并在自身 close() 中负责调用内层流的 close()。如果手动提前关闭内层流,外层流后续 close() 可能抛出 IOException 或静默失败;反之,若只关闭外层而忽略内层(虽然 BufferedInputStream 会自动 delegate),则可能遗漏底层资源(如 FileInputStream 的文件句柄)或导致行为不一致。
- BufferedInputStream.close() 内部会调用其 wrapped InputStream 的 close()
- 但该机制依赖于“外层流未被提前关闭”,且仅限于标准 JDK 实现
- 自定义 Decorator 若未正确实现 close 委托,更需严格遵循顺序
典型嵌套示例与正确关闭方式
例如:new BufferedInputStream(new DataInputStream(new FileInputStream("a.txt"))) —— 这种三层嵌套应按如下方式关闭:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 调用最外层 BufferedInputStream 的 close()
- 它会自动触发 DataInputStream.close()
- DataInputStream 再调用 FileInputStream.close()
- 无需、也不应显式调用 DataInputStream 或 FileInputStream 的 close()
使用 try-with-resources 简化管理
推荐用 try-with-resources 自动处理关闭顺序,JVM 保证按声明逆序关闭(即先关最外层):
立即学习“Java免费学习笔记(深入)”;
try (FileInputStream fis = new FileInputStream("a.txt");
DataInputStream dis = new DataInputStream(fis);
BufferedInputStream bis = new BufferedInputStream(dis)) {
// 使用 bis 读取
} // bis → dis → fis 自动按此顺序关闭
注意:资源按声明顺序从左到右初始化,关闭时逆序执行,因此声明顺序直接影响 close 顺序。
常见误区提醒
- 不要为每个装饰器单独写 close() 调用,容易重复关闭或顺序错乱
- 不要在中间层流上调用 close() 后继续使用外层流,会导致 StreamClosedException
- 即使某层 close() 抛异常,外层仍会继续关闭后续资源(try-with-resources 的异常抑制机制)

















