finally 是 Java 中保障清理逻辑可靠执行的核心机制,无论异常是否发生、是否被捕获或是否存在 return/break,只要控制流进入 try 或 catch 块,finally 几乎总会执行(JVM 强制退出等极端情况除外)。

finally 是 Java 异常处理中保障清理逻辑可靠执行的核心机制,它不依赖异常是否发生、是否被捕获、甚至不依赖 return 或 break 的存在——只要控制流进入 try 或 catch 块,对应的 finally 就几乎一定会运行(JVM 强制退出等极端情况除外)。
何时必须用 finally 做清理
当操作涉及外部资源时,手动释放是刚需,而这些资源不会被 GC 自动回收:
- 文件流(FileInputStream、FileOutputStream)
- 数据库连接(Connection、Statement、ResultSet)
- 网络套接字(Socket、ServerSocket)
- 图形资源(如 AWT/Swing 中的 Graphics 对象)
- 自定义状态开关(如硬件控制标志、锁状态等)
标准写法:判空 + 嵌套 try-catch
直接在 finally 中调用 close() 可能抛出新异常,若原异常尚未处理,会被覆盖。标准做法是二次捕获:
FileInputStream fis = null;
try {
fis = new FileInputStream("data.txt");
// 读取逻辑
} catch (IOException e) {
System.err.println("读取失败:" + e.getMessage());
} finally {
if (fis != null) {
try {
fis.close(); // 可能再次抛 IOException
} catch (IOException e) {
System.err.println("关闭流失败:" + e.getMessage());
// 不 throw,避免掩盖原始异常
}
}
}
更现代的替代方案:优先用 try-with-resources
Java 7 起推荐使用 try-with-resources,它自动调用 AutoCloseable 实现类的 close(),语义更清晰、代码更简洁、异常处理更健壮(会抑制次要异常):
立即学习“Java免费学习笔记(深入)”;
try (FileInputStream fis = new FileInputStream("data.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {
String line = reader.readLine();
// 处理数据
} catch (IOException e) {
System.err.println("操作失败:" + e.getMessage());
}
// fis 和 reader 自动关闭,无需 finally 块
注意:只有实现了 AutoCloseable 接口的资源才适用;多个资源用分号分隔,按声明逆序关闭。
finally 的边界情况需留意
以下情形下 finally 仍会执行,但行为需特别注意:
- try/catch 中有 return:先计算 return 表达式,再进 finally,finally 执行完才真正返回(若 finally 也有 return,则覆盖原返回值)
- System.exit() 调用:JVM 立即终止,finally 不执行
- 线程被强制中断或 kill -9:无法保证执行
- finally 内抛出未捕获异常:会中断当前流程,覆盖 try/catch 中的异常


















