finally 会耍你
什么,在 finally 里修改变量,竟然对结果没影响?
我们来看看代码,是怎么回事(可以先在心里运行一下)
代码语言:javascript复制public class TryTest {
private static int test() {
int x = 1;
try {
System.out.println("A");
return x;
} catch (Exception e) {
System.out.println("D");
} finally {
System.out.println("B");
x;
}
System.out.println("C");
return x;
}
public static void main(String[] args) {
int result = test();
System.out.println(result);
}
}
答案是:
A B 2
疑惑:为什么不是 AB3,又为什么不是ABC3?
开始 debug
(1) 首先执行 try 中的语句,此时 x = 1
(2)然后执行 return x;此时x = 1
(3)由于没有抛出异常,此时不执行catch语句,继续执行 finally 的语句
(4)继续执行
(5)继续执行,会发现,再次回到 try {...} 中的代码,停留在 return x;
(6)再继续执行,就已经返回了,但返回值是 2,不是刚刚的3
System.out.println("B"); return x;
这两句压根就没有执行,返回值也不是我们预期的3,WF ?
这是怎么回事?
去查阅了一下官方资料,官方给出的解释是:
如果 try 语句里有 return,那么代码的行为如下:
- 如果有返回值,就把返回值保存到局部变量中
- 执行 jsr 指令跳到 finally 语句里执行
- 执行完 finally 语句后,返回之前保存在局部变量表里的值。(虽然执行 x 后,x的值为3,但是返回保存在局部变量中的x = 2)
然后再根据以上的 debug 调试以及解释说明就可以知道返回 x 为什么是 2 了
当执行到 return x 时,jvm 在执行完 x 后,会在局部变量表里另外分配一个空间来保存当前的 x 值。
注意,现在还没有把返回值给 result,而是继续执行 finally 语句里语句。
等执行完后再把之前保存的值(是2,不是3)返回给 result。
总结一下
- finally 语句在 try 或 catch 中的 return 语句执行之后,返回之前执行;
- 且 finally 里的修改语句不一定影响 try 或 catch 中 return 已经确定的值;
- 若 finally 里也有 return 语句,则覆盖 try 或 catch 中的 return语句直接返回。
什么情况下 finally 不会被执行
- try 语句没有被执行到,比如 在 try 语句执行之前就返回了,此时 finally 语句不会被执行的
- try 块中有 System.exit(); 这样的语句,这个语句会终止 Java 虚拟机,连虚拟机都停了,当然 finally 语句也不会被执行了。