【Java 开发日记】finally 释放的是什么资源?

【Java 开发日记】finally 释放的是什么资源?

这是一个非常经典且容易被误解的问题。很多人会脱口而出:“finally 就是用来释放资源的啊!”——但严格来说,finally 本身并不“释放”任何资源

finally 真正做的是:提供一个“无论如何都会执行”的代码块,而资源释放的代码通常写在 finally 里面

核心一句话

finally 块的典型用途是:放置资源清理代码,确保那些需要手动关闭/释放的系统资源(如文件、连接、锁等)在 try 块正常结束、return、break、continue、throw 异常等任何退出路径下都能被执行。

finally 最常用来释放/清理的资源类型

资源类型典型对象/接口释放方式(常见写法)为什么必须在 finally 里做?
文件流FileInputStream, FileOutputStream, BufferedReader, BufferedWriter 等close()不关闭会导致文件句柄泄漏、系统资源耗尽
数据库连接java.sql.Connection, Statement, ResultSetclose()连接池耗尽、数据库压力大
网络连接Socket, ServerSocket, HttpURLConnection 等close()端口占用、连接泄漏
JDBC 相关PreparedStatement, CallableStatement 等close()同数据库连接
锁(手动锁)ReentrantLockunlock()死锁风险
其他系统资源Scanner(老代码中常见)、RandomAccessFile 等close()底层依赖文件描述符
自定义资源一些需要手动释放的业务资源(如临时文件句柄、缓存引用等)自定义 cleanup 方法防止内存/资源泄漏

代码示例(传统写法)

FileInputStream fis = null;
try {
    fis = new FileInputStream("data.txt");
    // 读取文件...
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fis != null) {
        try {
            fis.close();          // 真正的资源释放动作在这里
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Java 7 之后:try-with-resources(强烈推荐)

从 Java 7 开始,绝大部分需要关闭的资源都实现了 AutoCloseable 或 Closeable 接口,这时应该优先使用 try-with-resources,它会自动调用 close(),代码更简洁、更安全。

try (FileInputStream fis = new FileInputStream("data.txt");
     BufferedInputStream bis = new BufferedInputStream(fis)) {
    // 使用 fis / bis
    // 不需要手动 close
} catch (IOException e) {
    e.printStackTrace();
}
// 这里 fis 和 bis 已经自动关闭了

try-with-resources 底层其实相当于在 finally 里自动调用了 close(),而且支持多个资源、异常抑制(suppressed exceptions)等高级特性。

常见误区与澄清

误区真相
finally 专门负责释放资源错!finally 只是保证执行,释放资源是我们自己写在 finally 里的代码
所有资源都要在 finally 里释放错!实现了 AutoCloseable 的资源优先用 try-with-resources
finally 里抛异常会覆盖 try/catch 的异常正确,但 Java 7+ 用 suppressed 机制记录了原始异常(getSuppressed())
finally 一定执行几乎一定,但有极少数极端情况不会执行(如 JVM 被 kill、System.exit()、死循环、电源断电)

现代 Java 开发建议(2025–2026 视角)

  1. 优先使用 try-with-resources(99% 的场景)
  2. 老代码/不支持 AutoCloseable 的资源才用传统 try-catch-finally + close()
  3. 永远不要在 finally 里做业务逻辑,只做清理工作
  4. ReentrantLock 这种手动锁也推荐写在 finally 里 unlock(虽然有 try-with-resources 风格的 Lock,但不常见)
  5. 日志记录可以在 finally 里做,但要小心别抛异常

一句话总结:

finally 本身不释放资源,它释放的是“开发者写在 finally 里的清理代码”,而这些清理代码通常是 close()unlock()dispose() 等动作,用来归还系统资源(文件句柄、数据库连接、socket、锁等)。

希望这篇日记把 finally 和资源释放的关系说清楚了。如果你还有疑问(比如 suppressed 异常怎么看、多个资源的关闭顺序、try-with-resources 的字节码实现等),随时问,我继续展开!

文章已创建 4631

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部