Java中正确关闭IO资源的核心是优先使用try-with-resources语法,要求资源实现AutoCloseable接口、声明于try括号内、多资源按声明逆序关闭,JVM自动保障close()调用且异常被正确抑制;传统方式须在finally中判空并嵌套处理close()异常。

Java中正确关闭IO资源的核心是确保流在使用后及时释放,避免资源泄漏。关键不在于“捕获异常后手动close”,而在于用更可靠的机制自动管理资源生命周期。
优先使用try-with-resources语法(JDK 7+)
这是最推荐的方式,编译器会自动生成finally块并调用close(),即使发生异常也能保证关闭。
- 要求资源类实现AutoCloseable接口(InputStream、OutputStream、Reader、Writer等都满足)
- 资源声明写在try括号内,多个资源用分号隔开,关闭顺序与声明顺序相反
- 无需显式调用close(),也不需要额外的finally块
示例:
try (FileInputStream fis = new FileInputStream("a.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("b.txt")) {
// 读写操作
int data;
while ((data = bis.read()) != -1) {
fos.write(data);
}
} catch (IOException e) {
// 只需处理业务异常,关闭由JVM保障
e.printStackTrace();
}
若必须用传统try-catch-finally,close必须放在finally中
手动关闭时,如果把close()写在try块里,一旦前面操作抛异常,close就不会执行;写在catch里又无法覆盖所有异常路径。
立即学习“Java免费学习笔记(深入)”;
- 在finally中调用close(),确保无论是否异常都会执行
- close()本身也可能抛IOException,需嵌套try-catch或声明throws
- 关闭前判空,防止null指针(尤其当构造流就失败时)
示例:
FileInputStream fis = null;
try {
fis = new FileInputStream("a.txt");
// 读取操作
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace(); // 或记录日志
}
}
}
注意多层包装流的关闭顺序和效果
像BufferedInputStream包装FileInputStream,只需关闭外层流(BufferedInputStream),其close()内部会自动调用底层流的close()。
- 不需要、也不应该分别关闭每一层流,否则可能重复关闭或引发异常
- 但要注意:某些装饰流(如PrintStream)的close()会刷新缓冲区并关闭底层流;而flush()只是刷缓冲,不关闭
- 如果需要单独刷新而不关闭,用flush();确定结束时,用close()
使用工具类简化关闭逻辑(可选)
Apache Commons IO提供了IOUtils,其closeQuietly()方法可安全关闭任意Closeable对象,忽略关闭过程中的异常。
- 适合遗留代码改造,或需兼容老JDK版本(
- 引入依赖后,一行代码即可关闭,且不抛异常干扰主流程
示例:
FileInputStream fis = null;
try {
fis = new FileInputStream("a.txt");
// ...
} finally {
IOUtils.closeQuietly(fis); // 自动判空 + 忽略close异常
}


















