finally块必定执行,前提是程序正常调度到该代码段;JVM通过异常表和栈帧退出逻辑强制保障,无论try正常结束、抛异常、含return/break/continue,均先执行finally再继续流程,仅System.exit()、JVM崩溃等底层失效时例外。

Java 中的 finally 块通过 JVM 层面的控制流保障机制实现“必然执行”,前提是程序能正常调度到该代码段——它不是靠语言语法“承诺”,而是由字节码异常表(exception table)和栈帧退出逻辑共同强制执行的。
执行保障来自 JVM 的结构化退出机制
只要线程进入 try 块并开始执行(哪怕只执行了一条指令),JVM 就会在当前方法的字节码中登记一个“退出钩子”:无论后续是自然结束、抛出未捕获异常、遇到 return/break/continue,还是被 catch 捕获后退出 try-catch 结构,JVM 都会拦截控制流,在真正离开该 try 范围前跳转至 finally 对应的字节码位置执行。
- 这个过程不依赖程序员是否写了 catch,也不关心异常类型是否匹配
- 即使 try 中调用了一个抛出 RuntimeException 的方法,JVM 仍先跑完 finally 再把异常往上扔
- return 值会被暂存到局部变量表,等 finally 执行完才真正返回
常见场景下都可靠执行
以下情况中,finally 总会在控制流离开 try 或 catch 后、方法真正退出前运行:
- try 正常执行完毕 → 紧接着执行 finally
- try 抛出异常且有匹配 catch → catch 执行完 → 执行 finally
- try 抛出异常但无匹配 catch → 在异常向上传播前执行 finally
- try 或 catch 中含 return → 先记录返回值 → 执行 finally → 再返回(除非 finally 自己 return)
- 循环内 try 中出现 break/continue → 当前迭代退出前执行 finally
不执行的极少数硬性例外
这些属于 JVM 无法继续调度 Java 代码的底层失效,已超出语言规范能保证的范围:
立即学习“Java免费学习笔记(深入)”;
- 调用
System.exit()或Runtime.getRuntime().halt() - 进程被操作系统强制终止(如
kill -9) - 系统断电、内核崩溃、物理硬件故障
- finally 自身抛出未捕获的
OutOfMemoryError等致命错误(此时 JVM 可能直接中止)
实际使用中的关键提醒
为确保 finally 发挥作用,需注意:
- 避免在 finally 中写 return —— 会覆盖原返回值,掩盖业务逻辑意图
- 关闭资源时若可能抛异常(如
close()),应在内部 try-catch 处理,防止吞掉原始异常 - 现代 Java 推荐优先用
try-with-resources替代手动 finally 关闭资源,更简洁且不易出错 - 死循环或无限递归若发生在 try 块开头、尚未进入 finally 登记点,则 finally 不会触发 —— 这不是 finally 失效,而是程序根本没走到“可保障”的位置


















