会。finally块总会执行,即使try中有return;JVM先暂存return值,再执行finally,最后返回暂存值;若finally含return则覆盖原返回值,否则仅做清理。

try里有return,finally还会执行吗
会。只要finally块存在且未被System.exit()或JVM崩溃等极端情况中断,它就一定会执行——哪怕try块里写了return。
关键在于:不是“先return再finally”,而是“先暂存return值,再执行finally,最后返回那个被暂存的值”。这导致一个常见误解:以为finally里改了变量就能改变返回值——对基本类型和不可变对象(如String)无效;对可变对象(如StringBuilder、自定义对象)可能生效,但属于危险操作,不推荐依赖。
finally修改返回值的边界情况
只有当finally块自身也包含return语句时,它才会真正覆盖try或catch中的return。此时,try里的return会被完全丢弃,程序直接从finally返回。
-
finally中无return:原return值被保留,finally仅做清理 -
finally中有return:立即返回,跳过try/catch中已计算但未送出的返回值 -
finally抛出异常:该异常会“吞掉”try中的return,调用方收到的是finally的异常
public static int test() {
try {
return 1;
} finally {
return 2; // 实际返回2,1被丢弃
}
}
为什么不能在finally里写return
这不是语法错误,但属于严重逻辑陷阱:
立即学习“Java免费学习笔记(深入)”;
- 掩盖真实退出路径:调用方无法区分是正常流程返回,还是
finally强行截断 - 破坏异常传播:如果
try抛了异常,finally的return会让异常彻底消失 - 违反直觉:多数开发者默认
finally只做资源释放,突然返回值会引发维护困惑
Java官方文档明确建议:不要在finally中使用return、throw或break等转移控制流的语句。
更安全的替代写法
把清理逻辑和返回逻辑分离。需要“执行后返回”的场景,优先用显式变量承载结果,确保控制流清晰:
public static String readFile(String path) {
BufferedReader reader = null;
String content = null;
try {
reader = new BufferedReader(new FileReader(path));
content = reader.readLine();
return content; // 明确在此决定返回什么
} catch (IOException e) {
return null;
} finally {
if (reader != null) {
try {
reader.close(); // 只做清理,不碰return
} catch (IOException ignored) {}
}
}
}
复杂点在于:return值的计算时机、finally对可变对象的副作用、以及JVM字节码层面的“暂存-执行-送出”三阶段模型。这些细节一旦忽略,调试时很容易误判执行顺序。










