try-with-resources按声明逆序关闭资源,即最后声明的先关、最先声明的后关;必须按依赖关系逆序声明(如FileInputStream→BufferedInputStream→DataInputStream),确保外层流先关闭以触发内层流正确释放。

只需关闭最外层流,或用 try-with-resources 按依赖逆序声明所有流,就能安全释放全部资源。关键不是“关几个”,而是“谁依赖谁”——外层流靠内层流活着,所以内层必须后关。
字节流嵌套(如 FileInputStream → BufferedInputStream → DataInputStream)
这类组合是纯二进制处理链,关闭时必须保证:DataInputStream 先关 → BufferedInputStream 再关 → FileInputStream 最后关。因为:
- DataInputStream.close() 会调用其包装的 BufferedInputStream 的 close()
- BufferedInputStream.close() 又会调用 FileInputStream 的 close()
- 若手动先关 FileInputStream,后续再调 DataInputStream.close() 就会抛
Stream closed
推荐写法:
try (FileInputStream fis = new FileInputStream("a.bin");BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis)) {
// 读取操作
}
JVM 按声明逆序关闭:dis → bis → fis,完全匹配依赖逻辑。
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
字符流嵌套(如 FileOutputStream → OutputStreamWriter → BufferedWriter)
这是文本写入典型链,涉及编码转换和行缓冲。同样要遵循“外层先关、底层后关”原则:
- BufferedWriter.close() 先 flush 缓冲区,再调 OutputStreamWriter.close()
- OutputStreamWriter.close() 再调 FileOutputStream.close()
- 若跳过 BufferedWriter,直接关 FileOutputStream,会导致缓存中的字符丢失
正确声明顺序(底层在前、包装在后):
try (FileOutputStream fos = new FileOutputStream("out.txt");OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
BufferedWriter bw = new BufferedWriter(osw)) {
bw.write("你好世界");
bw.flush(); // 关键场景建议显式刷一次
}
混合使用或含异常风险时的操作建议
当数据落地很关键(如保存配置、写日志),别只靠 close() 隐式刷盘:
- 在
try块末尾加flush(),让写失败暴露在主流程中 - 捕获异常后,检查
e.getSuppressed(),避免底层流关闭失败被掩盖 - 所有流必须在
try()中独立声明,不能只写最外层、也不能用匿名对象传入
哪些流其实可以不关?
内存类流(如 ByteArrayInputStream、ByteArrayOutputStream、StringReader、StringWriter)不持有外部资源,关与不关都不影响系统资源,但为统一风格,仍建议纳入 try-with-resources 管理。

















