Java:在try里面直接return,finally的代码会不会执行
·
近期在重构一个功能,发现代码中途可能会直接return,但是重构优化的时候要考虑其他的问题并处理异常,那么问题来了:Java里面try-catch-finally中,如果在try里面直接return,finally的代码会不会执行?
答案是:会,finally块中的代码一定会执行。
即使在try块中使用了return语句,Java也会保证在方法真正返回之前,先去执行finally块中的代码。
详细解释和执行顺序
- 执行try块:代码正常执行到
return语句。 - 计算返回值:计算
return语句后面的表达式的值,并将这个返回值暂存在一个临时变量中。此时,方法并没有立即返回。 - 执行finally块:Java转而开始执行finally块中的所有代码。
- 方法返回: finally块执行完毕后,方法再将之前暂存的返回值返回出去。
关键点:返回值是如何被影响的?
这里有一个非常重要的细微差别:如果finally块里也有return语句,它会覆盖try(或catch)块中的返回值。这通常被认为是一种不好的实践,因为它会掩盖try块中的原始返回意图,并且使代码难以理解。
让我们通过几个例子来加深理解:
示例1:finally执行,但不影响基本类型的返回值
public class FinallyExample {
public static void main(String[] args) {
System.out.println("Result: " + test());
}
public static int test() {
try {
System.out.println("Try block");
return 1; // 返回值 1 被暂存
} finally {
System.out.println("Finally block");
// finally 执行,但这里没有 return
}
}
}
输出:
Try block
Finally block
Result: 1
过程: return 1; 执行,值1被暂存 -> 执行finally -> 返回暂存的值1。
示例2:finally中的return覆盖了try中的返回值(不推荐!)
public class FinallyExample {
public static void main(String[] args) {
System.out.println("Result: " + test());
}
public static int test() {
try {
System.out.println("Try block");
return 1;
} finally {
System.out.println("Finally block");
return 2; // 这个 return 会覆盖 try 中的 return
}
}
}
输出:
Try block
Finally block
Result: 2
过程: return 1; 执行,值1被暂存 -> 执行finally -> 遇到return 2;,值2成为新的返回值 -> 方法返回2,之前暂存的1被丢弃。
示例3:finally修改引用类型对象的内部状态
public class FinallyExample {
public static void main(String[] args) {
System.out.println("Result: " + test().getValue());
}
public static MyObject test() {
MyObject obj = new MyObject();
obj.setValue(10);
try {
System.out.println("Try block");
obj.setValue(20);
return obj; // 返回的是对象引用(地址)的副本
} finally {
System.out.println("Finally block");
obj.setValue(30); // 通过引用修改对象内部的状态
}
}
static class MyObject {
private int value;
public int getValue() { return value; }
public void setValue(int value) { this.value = value; }
@Override
public String toString() { return "MyObject{value=" + value + '}'; }
}
}
输出:
Try block
Finally block
Result: 30
过程:
return obj;执行时,返回的是对象obj的引用地址的副本,并暂存。- 执行finally块,通过这个引用(
obj)修改了对象的内部状态(value从20变为30)。 - 方法返回的是之前暂存的那个引用地址,而通过这个地址找到的对象,其
value已经被finally修改为30了。
总结
| 场景 | finally是否执行 | 说明 |
|---|---|---|
try 中有 return |
是 | 先暂存返回值,执行finally,再返回。 |
try 和 finally 中都有 return |
是 | finally中的return会覆盖try中的return。 |
try 中抛出异常 |
是 | 先执行finally,再将异常抛出给调用者。 |
try 中调用 System.exit(0) |
否 | System.exit(0)会直接终止JVM进程。 |
| 守护线程因所有非守护线程结束而终止 | 可能否 | 如果JVM在finally执行前就退出了,则不会。 |
最佳实践:
- 避免在finally块中使用return语句,这会掩盖try和catch块中的异常和返回语句,导致难以调试的bug。
- finally块通常用于释放资源,如关闭文件流、数据库连接等,以确保资源在任何情况下都能被正确清理。
更多推荐


所有评论(0)