finally块无论是否发生异常都会执行,适合资源清理;但System.exit()、JVM崩溃等极端情况会跳过它;避免在finally中return,优先使用try-with-resources。

finally 块在异常未抛出时也会执行
只要 try 块开始执行,无论是否发生异常、是否被 catch 捕获,finally 块都会执行(除非 JVM 退出或调用 System.exit())。这意味着它适合做资源清理这类“无论如何都要做的事”。
常见误判是认为 finally 只在异常发生时才运行——实际不是。比如下面这段代码:
public static void main(String[] args) {
try {
System.out.println("try");
return; // 即使这里 return,finally 仍会执行
} finally {
System.out.println("finally");
}
}
输出是:
try finally
-
return不会跳过finally -
break、continue在try中也一样,finally照常执行 - 如果
finally里也有return,它会覆盖try或catch中的返回值(不推荐)
finally 中修改返回值会覆盖原始结果
当 try 或 catch 中有 return,而 finally 里也有 return,JVM 会丢弃前面的返回值,以 finally 的为准。这是容易踩坑的地方。
立即学习“Java免费学习笔记(深入)”;
public static String getValue() {
try {
return "try";
} finally {
return "finally"; // 这个值最终被返回
}
}
调用 getValue() 得到的是 "finally",不是 "try"。
- 基本类型和不可变对象(如
String)会被完全覆盖 - 可变对象(如
StringBuilder)若在finally中被修改,会影响返回结果,但不是因为“覆盖”,而是因为引用没变 - 这种写法会让逻辑难以追踪,应避免在
finally中写return
资源释放别只靠 finally,优先用 try-with-resources
手动在 finally 里关流(如 close())容易漏判 null 或重复关闭,且代码冗长。Java 7+ 推荐用 try-with-resources 自动管理实现了 AutoCloseable 的资源。
try (FileInputStream fis = new FileInputStream("a.txt")) {
// 使用 fis
} catch (IOException e) {
// 处理异常
} // fis.close() 自动调用,无需 finally
-
try-with-resources会在语句结束前自动调用close(),即使发生异常 - 多个资源用分号隔开,关闭顺序与声明顺序相反
- 如果必须手写
finally(比如老版本 JDK 或非AutoCloseable对象),记得判空再关:if (conn != null) conn.close();
finally 不会执行的几种情况
虽然 finally “几乎总执行”,但以下场景它确实不会跑:
- JVM 直接退出:
System.exit(0)在try中调用,finally被跳过 - 线程被强制中断(如
Thread.stop(),已废弃但仍有影响) -
try块还没开始执行就发生致命错误(如StackOverflowError在进入try前爆发) - 操作系统 kill -9 强杀进程
这些属于极端情况,日常开发中不用过度担忧,但写关键清理逻辑(如解锁、回滚事务)时,得清楚 finally 并非 100% 可靠——真正高保障的清理往往需要配合超时、心跳或外部协调机制。










