• finally语句块对返回的影响


     Java中用于异常处理的语句方法为:

    try {
        //...
    } catch (Excaption e){
        //...
    } finally {
        //...
    } 

    其中finally语句块是一定会执行的,不论是正常返回还是抛出异常。

    那么就引出一个问题:当在 try/catch 语句中已经 return 返回一个变量,此时再次在finally中操作返回变量或重新return会对原来的返回值造成什么影响?

    1、finally中修改返回变量

        /** 在finally语句块中修改返回变量的值 */
        static int testFinallyAndReturn1(){
            int i=10;
            try{
                return i;
            }finally{
                i=i+1;
            }
        }
    public static void main(String[] args) { int return1 = testFinallyAndReturn1(); System.out.println(return1); //结果为10 }

    结果返回依然是return的值,可以说在finally中操作已经return的变量,不会对返回结构有影响。

    口说无凭,使用 javap -c 命令反编译看看:

      static int testFinallyAndReturn1();
        Code:                                   模拟栈和局部变量表的存储内容,栈的左侧为栈顶,局部变量表依次索引为0,1,2,...
           0: bipush        10         # 向操作数栈中放入常量10                           栈:10           局部变量表:
           2: istore_0                 # 将栈顶元素放入局部变量表的slot 0位置  值为10      栈:             局部变量表:10
           3: iload_0                  # 取出局部变量表slot 0的值入栈    值为10            栈:10           局部变量表:10
           4: istore_1                 # 栈顶元素存入slot 1    值为10                     栈:             局部变量表:10 10
           5: iload_0                  # 局部变量表slot 0入栈  值为10                      栈:10           局部变量表:10 10
           6: iconst_1                 # 常量1入栈                              栈:1 10         局部变量表:10 10
           7: iadd                     # 栈顶2个元素出栈并相加,结果再入栈  值为11            栈:11           局部变量表:10 10
           8: istore_0                 # 栈顶元素存入slot 0   值为11                    栈:                       11 10
           9: iload_1                  # slot 1入栈                                   栈:10                     11 10   
          10: ireturn                  # 栈顶元素返回
          11: astore_2                 # 下面是出现异常时的指令。。。。
          12: iload_0
          13: iconst_1
          14: iadd
          15: istore_0
          16: aload_2
          17: athrow
        Exception table:
           from    to  target type
               3     5    11   any

     从上面的字节码指令可以看到,虽然return代码写在前面,但是在执行字节码时,还是先执行finally的加1操作。

     finally做加法操作与return操作的变量,分别被存储到局部变量表不同slot中,所以finally中操作变量不会影响返回值。

    2、finally中再次return

    /** 在finally语句块中修改返回变量的值,并再次返回变量 */
    static int testFinallyAndReturn2(){
        int i=10;
        try{return i;
        }finally{
            i=i+1;
            return i;
        }
    }
    //----------------------
    public static void main(String[] args) {
        int return2 = testFinallyAndReturn2();
        System.out.println(return2); //11
    
    }

    结果:finally中返回的值会覆盖掉之前return的值

    字节码如下:

      static int testFinallyAndReturn2();
        Code:
           0: bipush        10
           2: istore_0
           3: iload_0
           4: istore_1      # 这里没有用到???
           5: iload_0
           6: iconst_1
           7: iadd
           8: istore_0
           9: iload_0       # 不同点在这里,返回指令前入栈的是slot 0 值为11
          10: ireturn
          11: astore_2
          12: iload_0
          13: iconst_1
          14: iadd
          15: istore_0
          16: iload_0
          17: ireturn
        Exception table:
           from    to  target type
               3     5    11   any

    3、finally的返回值会覆盖掉抛出的异常

    如下,这段代码会正常返回11,而不是抛出异常。

        static int testFinallyAndReturn2(){
            int i=10;
            try{
                int a = i/0;
                return i;
            }finally{
                i=i+1;
                return i;
            }
        }
    这段是finally中无返回值时的部分指令:

      15: astore_3
      16: iload_0
      17: iconst_1
      18: iadd
      19: istore_0
      20: aload_3
      21: athrow     #抛出异常


    //----------------------------------------------
    这个是finally中有返回值时的部分指令:

      15: astore_3
      16: iload_0
      17: iconst_1
      18: iadd
      19: istore_0
      20: iload_0
      21: ireturn    #返回

    finally中如果有返回值语句,就会用return指令覆盖掉异常抛出指令。所以说最好不要在finally中返回结果。

    4、简单总结

    • finally语句块中仅修改返回变量,不会影响最终的返回结果
    • finally语句块中有返回语句,会覆盖之前的返回值
    • finally语句块中有返回语句,会覆盖抛出的异常,使异常无法抛出
  • 相关阅读:
    POI数据类型转换
    RSA加密解密——绕过OpenSSL
    STS热部署,springboot项目中修改代码不用重新启动服务
    List || Lists
    java解析复杂json数据
    Sublime Text 3 全程详细图文原创教程
    SpringBoot外调的几种方式 || http、https配置
    JPA对原生SQL的支持
    基于UDP协议的网络编程
    基于TCP协议的网络编程
  • 原文地址:https://www.cnblogs.com/liuyiyuan/p/13818101.html
Copyright © 2020-2023  润新知