一句话总结:
finally 里的 return 像霸道总裁——不管 try/catch 怎么折腾,最终都得听我的!
一、基础规则:finally 必执行
- 无论 try/catch 里是否报错、是否有 return,finally 代码块必定执行(除非 JVM 崩溃)。
- 常见用途:关闭文件、释放数据库连接等清理操作。
public int demo() {
try {
System.out.println("try 执行");
return 1;
} catch (Exception e) {
return 2;
} finally {
System.out.println("finally 执行");
}
}
// 输出:
// try 执行
// finally 执行
// 返回值:1
二、finally 里写 return 会怎样?
场景 1:finally 无 return
- try/catch 的 return 暂存结果,等 finally 执行完再返回。
- 值类型:返回的是 try/catch 中暂存的原始值(finally 里修改无效!)。
- 引用类型:修改对象属性会影响结果(因为引用地址不变)。
public int demo() {
int num = 0;
try {
num = 1;
return num; // 暂存 num=1
} finally {
num = 2; // 修改无效!最终返回 1
}
}
场景 2:finally 有 return
- 直接覆盖 try/catch 的返回值,且会吞掉异常(极其危险!)。
public int demo() {
try {
throw new RuntimeException("报错啦!");
} catch (Exception e) {
System.out.println("捕获异常");
return 1;
} finally {
return 666; // 最终返回 666,异常被吞!
}
}
// 输出:捕获异常
// 返回值:666(异常消失!)
三、为什么 finally return 会吞异常?
-
JVM 执行逻辑:
- try 里抛异常 → catch 处理 → 准备返回 1。
- 执行 finally → 遇到 return 666 → 直接覆盖返回值,并结束方法。
- 原本要抛的异常被丢弃,像从未发生过!
四、血泪教训:千万别在 finally 里写 return!
-
坑点总结:
- 覆盖返回值:导致预期外的结果。
- 吞掉异常:错误被隐藏,极难调试!
- 代码反直觉:其他开发者容易踩坑。
五、正确姿势:finally 只做清理,别 return!
public void readFile() {
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
// 读文件...
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close(); // 只做清理!
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
总结口诀:
“try/catch 可 return,finally 必执行。
若在 finally 写 return,返回值被覆盖,异常全失踪!”