应优先使用 try-with-resources 而非裸写 finally.close(),因其自动判空、逆序关闭、异常抑制且避免 nullpointerexception、异常掩盖及资源未释放等问题;若必须用 finally,则需声明资源为 null、判空并用 try-catch 包裹 close。

在 Java 中,finally 块本身不是释放资源的推荐方式,尤其对于数据库连接、文件流等需要显式关闭的资源。直接在 finally 中手动 close 容易出错(如未判空、异常掩盖、重复关闭),现代写法应优先使用 try-with-resources 语句。但若因兼容性或特殊逻辑必须用 finally,需严格遵循安全关闭模式。
为什么避免裸写 finally.close()?
常见错误包括:
- 资源变量为 null 时调用 close() 抛 NullPointerException
- close() 自身抛 IOException/SQLException,掩盖 try 或 catch 中的原始异常
- 多个资源时,一个 close 失败后后续资源未关闭(缺乏兜底)
- 忘记将资源声明为 final 或有效作用域内可见,导致 finally 中不可访问
正确使用 finally 的安全关闭模板
若必须用 finally(例如旧 JDK 环境、资源创建逻辑复杂无法放入 try-with-resources 的括号中),按以下结构处理:
- 资源变量声明在 try 外,初始化为 null
- 在 finally 中判空 + try-catch 包裹每个 close()
- 不抛出 close 异常,或仅记录日志,不中断主流程
示例(数据库连接):
Connection conn = null;
try {
conn = dataSource.getConnection();
// 执行查询...
} catch (SQLException e) {
// 处理业务异常
} finally {
if (conn != null) {
try {
conn.close(); // 可能抛 SQLException
} catch (SQLException e) {
// 记录警告,不抛出
logger.warn("Failed to close database connection", e);
}
}
}
更优解:优先用 try-with-resources(JDK 7+)
它自动调用 close(),且保证即使构造函数或 close() 抛异常,资源仍被释放,并支持异常抑制(suppressed exception)机制:
- 资源类必须实现 AutoCloseable 接口(InputStream、Connection、Statement 等均已实现)
- 多个资源用分号分隔,按声明逆序关闭
- 无需判空,null 赋值会跳过 close 调用
示例(带事务的数据库操作):
try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement("SELECT ...");
ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
// 处理结果
}
} catch (SQLException e) {
// 主异常被捕获,close 过程中的异常被抑制并可获取
}
额外提醒:连接池与流的特殊注意事项
数据库连接通常来自连接池(如 HikariCP、Druid),调用 close() 实际是归还连接而非销毁,但仍必须调用;文件流若包装了缓冲(如 BufferedInputStream),只需关闭最外层流,内部会自动级联关闭底层流。不要手动关闭多层流,否则可能重复关闭或关闭已关闭流。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











