try和finally里的return

时间:2021-11-09 20:20:27

finally一定会执行吗?回答当然是否定的,假如在try里执行了System.exit(0)就不会再去执行finally了,守护线程中的finally碰到非守护线程全部退出的时候也可能执行不到。

又如下面的代码,会打印什么内容?

public class Test {    publicstatic void main(String... args) {        System.out.println(getValue1());        System.out.println(getValue2());    }     publicstatic int getValue1() {        inti1 = 0;        inti2 = 1;        try{            returni1;        }finally {            returni2;        }    }     publicstatic int getValue2() {        inti = 1;        try{            returni;        }finally {            i++;        }    }}

这个问题可以通过反编译查看字节码指令来解释,编译后再运行javap -c Test即可得到方法要执行的指令,接下来分别对两个方法做个分析

以下对字节码的解释中【】表示栈,左边表示栈顶

public static int getValue1();
Code:
0:   iconst_0 //将0入栈,栈内容【0】
1:   istore_0 //将栈顶元素弹出,也就是0,存到局部变量区索引为0的变量中(也就是i1),栈内容【】,(0,1)这两个指令是由int i1 = 0生成的
2:   iconst_1 //将1入栈,栈内容【1】
3:   istore_1 //将栈顶元素弹出,也就是1,存到局部变量区索引为1的变量中(也就是i2),栈内容【】,(2,3)这两个指令是由int i2 = 1生成的
4:   iload_0  //将局部变量区索引为0的变量(也就是i1)值入栈,栈内容【0】
5:   istore_2 //将栈顶元素弹出,也就是0,存到局部变量区索引为2的变量中(代码中没有声明,这是javac生成的临时变量,再此记为tmp1),栈内容【】
6:   iload_1  //将局部变量区索引为1的变量(也就是i2)值入栈,栈内容【1】
7:   ireturn  //将栈顶元素弹出,也就是1,并返回
8:   astore_3 //(8,9,10)属异常处理部分,这段代码不会出现异常,故执行不到下面的指令
9:   iload_1
10:  ireturn
Exception table:
from   to  target type
4     6     8   any
8     9     8   any

可见如果finally和try里都有执行了return,try里的return的值会被废弃。

public static int getValue2();
Code:
0:   iconst_1  //将1入栈,栈内容【1】
1:   istore_0  //将栈顶元素弹出,也就是1,存到局部变量区索引为0的变量中(也就是i),栈内容【】,(0,1)这两个指令是由int i = 1生成的
2:   iload_0   //将局部变量区索引为0的变量(也就是i)的值入栈,栈内容【1】
3:   istore_1  //将栈顶元素保存到局部变量区索引为1的变量中(代码中未声明此变量,在此记为tmp1),栈内容【】
4:   iinc    0, 1 //将局部变量区索引为0的变量加1,栈内容【】
7:   iload_1   //将局部变量区索引为1的变量(即tmp1)的值入栈,栈内容【1】
8:   ireturn   //弹出栈顶值并返回,即返回1
9:   astore_2  //以下是发生异常时的处理代码,这段代码不会抛出异常,后面的指令就不会执行到了
10:  iinc    0, 1
13:  aload_2
14:  athrow
Exception table:
from   to  target type
2     4     9   any
9    10     9   any

由此可见,在try里返回值会先存到一个临时变量中,finally里改变的是原始变量,改完之后再将临时变量的值返回,也就是说在finally里改变返回值变量并不影响返回值本身。