try catch finally的底层原理

来源:https://blog.csdn.net/lwd512768098/article/details/114728720

昨晚参加一个面试,被问到try catch finally相关的知识,虽然之前了解过其中奇怪的用法,特别有return的情况,但是由于时间久远,完全忘了,导致这个问题回答不是很好,只是知道finally无论是否发生异常都会执行的(但是忘了含有return的情况是怎么处理的了),finally常常用来关闭一些资源,像文件,连接等。

finally终究执行

我们先来验证一下finally终究执行

public static int test() { 
        int i = 1;
        try { 
            i++;
        } finally { 
            System.out.println("finally yeah!");
        }
        return i;
    }

    public static void main(String[] args) { 
        System.out.println(test());
    }

输出为

62e181d52723f1605fd5fc6a45a69049.png
public static int test() { 
        int i = 1;
        try { 
            i++;
            throw new Exception();
        } catch (Exception e) { 
            System.out.println("Exception yeah!");
        } finally { 
            System.out.println("finally yeah!");
        }
        return i;
    }

    public static void main(String[] args) { 
        System.out.println(test());
    }
27c4acdf184c14dfd0430fbf3346e046.png

从上面两个例子中我们可以看到,无论是正确运行try块还是在try块发生了异常,finally块都是被执行的搜索公众号互联网架构师回复“2T”,送你一份惊喜礼包。

带有return的情况

finally不带return的情况

对于return情况的话,只要记住一句话就行,如果finally里面有return, 那么就会覆盖try块或者catch里面的return内容,否则的话,在执行finally的内容之前(try块或者catch里面有return语句),会计算好try或者catch里面的return表达式的值,然后保存到另一个局部变量,当执行fianlly的时候,会重新加载这个局部变量作为返回值,因此在finally的操作不会影响返回值,下面我们字节码来看看内部的工作原理。

public static int test() { 
        int i = 1;
        try { 
            i++;
            return i;
        } finally { 
            i++;
            System.out.println("finally yeah!");
        }
    }

    public static void main(String[] args) { 
        System.out.println(test());
    }

第一个问题:在try块中含有return语句,你觉得finally语句还有执行么?
第二个问题:最终结果是多少?

f5dbf2bb4a54efd38a6b22d2ba155a60.png

从上面可以看到,尽管try块里面有return, 但是finally块仍然执行了,你肯定会好奇,那为啥返回值是2呢,finally里面不是还进行了i++么。搜索公众号互联网架构师回复“2T”,送你一份惊喜礼包。

简单分析一下,从结果看,finally仍然执行,说明try的return语句是还没执行的,下面我们看看字节码。

3706a87622a908244d27c90cc9bb6d93.png

上面图片已经标注很清楚了,如果还不明白的话,可以先去看一下这几个字节码命令,还是挺简单的,注意的是,JVM操作都是基于操作数栈的。

总结一下,总体的意思就是,当执行完try块的时候,会计算return表达式的值,然后把这个返回值存在另一个临时变量里面,最后返回的时候会重新读取存放的变量,因此在finally后面无论如何修改,都不会影响返回值(除非finally里面含有return,这个我们在下面讨论)

finally带有return

上面的情况是try或者catch里面含有return,finally没有return, 那么fianlly里面如何修改返回值是不会影响最后的返回值。下面讨论finally里面含有return的情况。

public static int test() { 
        int i = 1;
        try { 
            i++;
            return i;
        } finally { 
            i++;
            System.out.println("finally yeah!");
            return i;
        }
    }

    public static void main(String[] args) { 
        System.out.println(test());
    }

相信各位能够正常猜出结果了

708ae9cd8570f8506784a23b61229ef1.png

没错,返回了3,说明finally对i的修过是其效果的,我们从字节码看看原因:

9cacbcb98e55b2451fa98a20f95d82f5.png

从上图可以看到,在返回之前,加载的是0槽位的变量,这时0槽位的变量的值是3,1槽位的变量是2,所以返回的3。

由上可以得知,当finally中含有return的时候,会覆盖之前try或者catch(上面没有贴出实验,需要验证的可以去验证,作者本人是验证过了)里面的返回值的搜索公众号互联网架构师回复“2T”,送你一份惊喜礼包。

try, catch, finally均没有return语句

这种情况比较简单,跟finally含有return类似

public static int test() { 
        int i = 1;
        try { 
            i++;
        } finally { 
            i++;
            System.out.println("finally yeah!");
        }
        return i;
    }

    public static void main(String[] args) { 
        System.out.println(test());
    }
85b7f5c2c928e017cbc15be621ee51d7.png

总结

这里总结一下,只要finally里面没有return语句,那么返回值就由try或者catch的return语句决定,否则由finally的return语句决定

 
 
PS:如果觉得我的分享不错,欢迎大家随手点赞、转发、在看。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值