finally 总在 try 或 catch 执行后执行,即使 try 中 return 也会先暂存结果再进 finally;若 finally 含 return,则直接返回其值并覆盖 try/catch 的返回值。

try catch finally 的执行顺序到底是什么
无论是否抛出异常,finally 块一定会执行(除非 JVM 直接退出,比如调用 System.exit())。但很多人误以为 finally 总是在 catch 之后才跑——其实只要进入 try 块,哪怕中间 return 了,finally 也会插进来执行一次。
典型陷阱:try 中有 return,finally 也改了返回值(比如修改了引用对象的字段,或在 finally 里又写了个 return),结果实际返回的是 finally 的值。
-
try正常执行完 → 走finally→ 返回 -
try抛异常 → 匹配到catch→ 执行catch→ 执行finally→ 返回(或再抛) -
try里return→ 暂存返回值 → 进finally→finally执行完 → 返回暂存值(除非finally自己return)
finally 里写 return 会覆盖 try/catch 的返回值
这是最易被忽略的语义陷阱。一旦 finally 中出现 return,它会直接终结整个方法,前面 try 或 catch 中的 return 全部作废。
public static String test() {
try {
return "from try";
} catch (Exception e) {
return "from catch";
} finally {
return "from finally"; // ✅ 实际返回这个
}
}
运行结果永远是 "from finally"。即使 try 没抛异常、没进 catch,也一样被覆盖。
立即学习“Java免费学习笔记(深入)”;
- 不要在
finally里写return,除非你明确要压制所有上游返回逻辑 - 资源清理(如
close())可以放finally,但别让它带控制流 - JDK 7+ 推荐用 try-with-resources 替代手写
finally关流,更安全
try catch finally 和 try with resources 的关键区别
传统 try-catch-finally 需手动调用 close(),容易漏写、重复写、或在 catch 中抛新异常导致原异常丢失;而 try-with-resources 在字节码层面保证资源自动关闭,且能保留原始异常(通过 suppressed 机制)。
try (FileInputStream fis = new FileInputStream("a.txt")) {
// 读操作
} catch (IOException e) {
// e 是主异常,fis.close() 失败会作为 suppressed 异常附加
}
-
try-with-resources要求资源实现AutoCloseable - 多个资源用分号分隔,关闭顺序与声明顺序相反
- 如果
try块抛异常,且close()也抛异常,后者会被addSuppressed(),不会掩盖前者 - 老式
finally关流时,若close()抛异常,可能吞掉try中的真正问题
finally 不执行的几种真实情况
虽然文档说 finally “几乎总执行”,但工程中真有例外。这些不是理论边缘 case,而是线上可能踩到的坑:
- JVM 被外部强制终止:如
kill -9进程、容器被 OOM kill -
try或catch中调用了System.exit(0) - 线程被中断且未响应(极少见),或发生
StackOverflowError/OutOfMemoryError导致 JVM 状态异常 -
finally所在方法被内联优化?不会——JVM 规范强制保障finally语义,优化不会跳过它
所以,别把关键释放逻辑(比如解锁、回滚事务)只押在 finally 上而不加超时或兜底校验;对必须确保的动作,考虑结合守护线程或外部看门狗。










