finally 语句执行了等于没执行,原来里面还有玄机

2020-07-03 14:35:36 浏览数 (1)

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,那么代码的行为如下:

  1. 如果有返回值,就把返回值保存到局部变量中
  2. 执行 jsr 指令跳到 finally 语句里执行
  3. 执行完 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 语句也不会被执行了。

0 人点赞