只需关闭最外层流,底层流会自动按链式调用依次关闭——这是装饰者模式的内置行为,不是靠手动控制顺序实现的;包装流在 close() 中主动调用被包装流的 close(),该逻辑由 jdk 源码强制实现,多层嵌套也只需关最上层,用 try-with-resources 时需按依赖关系从底层到顶层声明资源。

只需关闭最外层流,底层流会自动按链式调用依次关闭——这是装饰者模式的内置行为,不是靠手动控制顺序实现的。
包装流的关闭本质是链式调用
字符流(如 BufferedReader)或缓冲流(如 BufferedInputStream)在构造时接收一个底层流作为参数,并在其 close() 方法中主动调用该底层流的 close()。这个逻辑写死在 JDK 源码里:
- BufferedReader.close() → 调用内部 InputStreamReader.close()
- InputStreamReader.close() → 调用内部 StreamDecoder.close()
- StreamDecoder.close() → 调用传入的 InputStream.close()(比如 FileInputStream)
整个链条是单向、向下的,只要最上层流关闭,所有被它包装的流都会被顺次释放。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
声明顺序决定关闭顺序(仅针对 try-with-resources)
使用 try-with-resources 时,JVM 不看“谁包谁”,只看资源在 try 括号中的声明顺序:先声明的后关闭(LIFO),所以必须按依赖关系从底层到顶层写:
- ✅ 正确:
try (FileInputStream fis = new FileInputStream("a.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(isr)) { ... } - ❌ 错误:把
BufferedReader写在FileInputStream前面 —— 编译可能通过,但实际创建了两个独立的底层流实例,导致重复关闭或“Stream closed”异常
绝对不要手动关闭多层流
显式调用多个 close() 不仅多余,还容易出错:
- 先关
FileInputStream,再关BufferedReader→ 后者读或关时抛IOException: Stream closed - 同时关所有三层 → 底层流可能被多次
close(),某些实现会静默失败或报错 - 只有最外层流需要你关注;中间和底层流的
close()是它的内部职责
异常场景下依然安全
即使 readLine() 抛出异常,try-with-resources 仍会确保所有已成功初始化的资源按逆序调用 close()。比如:
- 如果
FileInputStream和InputStreamReader初始化成功,但BufferedReader构造失败 → JVM 只关前两个,且按isr.close()→fis.close()执行 - 若某层
close()抛异常,JVM 会将其压制(suppressed),主异常仍保留,调试时可通过getSuppressed()查看
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










