finally不关闭资源,仅保证执行;需手动判空、单独try-catch每个close()并按依赖逆序关闭;推荐使用try-with-resources自动安全关闭。

finally 关键字本身不关闭资源,它只保证其中的代码一定会执行;能否真正关掉数据库连接或 IO 句柄,取决于你写的关闭逻辑是否健壮——重点是判空、捕获异常、控制顺序。
资源变量必须声明在 try 外
Connection、PreparedStatement、InputStream 等对象要初始化为 null,并声明在 try 块之外,否则 finally 根本访问不到它们:
- 正确写法:Connection conn = null; PreparedStatement stmt = null; InputStream is = null;
- 错误写法:try { Connection conn = DriverManager.getConnection(...); } finally { conn.close(); } → 编译报错,conn 不可见
每个 close() 都要单独 try-catch + 判空
close() 方法可能抛出 SQLException 或 IOException,一旦未捕获,就会中断后续所有关闭操作。不能共用一个 try-catch,也不能直接吞掉异常:
- 必须对 rs.close()、stmt.close()、conn.close() 各自加 if (xxx != null) + 单独 try-catch
- 异常建议用 logger.warn("关闭 ResultSet 失败", e),而不是 printStackTrace()
- 不要在 catch 里 throw 或 return,否则会覆盖 try 块中原本的业务异常
关闭顺序不能错
资源之间有依赖关系,反序关闭容易触发“connection closed”类异常:
- JDBC 场景:ResultSet → Statement → Connection
- IO 流场景:子流 → 父流(如 BufferedInputStream → FileInputStream)
- 原因:ResultSet 和 Statement 内部持有 Connection 引用,提前关 Connection 会导致前者失效
比 finally 更推荐 try-with-resources
Java 7+ 提供的 try-with-resources 是更安全、简洁的替代方案,前提是资源类型实现 AutoCloseable(JDBC 4.0+ 的 Connection/Statement/ResultSet、所有标准 IO 流都满足):
- 自动按声明逆序调用 close()
- 内部处理了异常抑制(suppressed exception),不会掩盖主异常
- 无需手动判空、无需写冗长的 finally 块
- 示例:try (Connection conn = ds.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql); ResultSet rs = stmt.executeQuery()) { ... }










