栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JAVA之try{}catch{}finally{}

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JAVA之try{}catch{}finally{}

前言

最近遇到一个try->catch->finally->return问题的变式,由于只知道是这么个顺序,但不知其原理,所以问题稍微变下就答不上来了。现在从字节码角度来分析这个问题。

代码

Sample1

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

    public static int finallyTest() {
        int a;
        try {
            a = 1;
            if (a == 1) {
                throw new RuntimeException("deliberate...");
            }
            return a;
        } catch (RuntimeException e) {
            a = 2;
            if (a == 2) {
                throw new RuntimeException("deliberate1...");
            }
            return a;
        } finally {
            a = 3;
            return a;
        }
    }
}

Sample2

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

    public static int finallyTest() {
        int a;
        try {
            a = 1;
            if (a == 1) {
                throw new RuntimeException("deliberate...");
            }
            return a;
        } catch (RuntimeException e) {
            a = 2;
            if (a == 2) {
                throw new RuntimeException("deliberate1...");
            }
        } finally {
            a = 3;
        }
        return a;
    }
}

上述两段代码的区别就在于finally代码块内是否有return语句;猜下两段代码执行的效果。

这里给出结论:

  • Sample1打印3;
  • Sample2抛出异常;
字节码

我们现在从字节码入手开始分析, ##后为笔者注释内容

Sample1

public static int finallyTest();
    Code:
       0: iconst_1 ## 从常量池里获取整数1
       1: istore_0 ## 将值存入第一个整型变量
       2: iload_0 ## 加载第一个整型变量的值
       3: iconst_1 ## 从常量池里获取整数1
       4: if_icmpne     17 ## 比较 如果不符合条件 跳到17行
       7: new           #5                  // class java/lang/RuntimeException
      10: dup
      11: ldc           #6                  // String deliberate...
      13: invokespecial #7                  // Method java/lang/RuntimeException."":(Ljava/lang/String;)V
      16: athrow ## 抛异常,到下方的异常表去查询目标命令行,这里是跳到23行
      17: iload_0 ## 加载第一个整型变量的值
      18: istore_1 ## 将值存入第二个整型变量 这里很重要,这是一个匿名变量
      19: iconst_3 ## 从常量池里获取整数3 这里是finally的代码块
      20: istore_0 ## 将值存入第一个整型变量
      21: iload_0 ## 加载第一个整型变量的值
      22: ireturn ## 返回
      23: astore_1 ## 将引用值存入第一个引用变量,这里是异常对象
      24: iconst_2 ## 从常量池里获取整数2 这里是catch的代码块
      25: istore_0 ## 将值存入第一个整型变量
      26: iload_0 ## 加载第一个整型变量的值
      27: iconst_2 ## 从常量池里获取整数2
      28: if_icmpne     41 ## 比较 如果不符合条件 跳到41行
      31: new           #5                  // class java/lang/RuntimeException
      34: dup
      35: ldc           #8                  // String deliberate1...
      37: invokespecial #7                  // Method java/lang/RuntimeException."":(Ljava/lang/String;)V
      40: athrow ## 抛异常,到下方的异常表去查询目标命令行,这里是跳到47行
      41: iload_0 ## 加载第一个整型变量的值
      42: istore_2 ## 将值存入第三个整型变量 这里很重要,这是一个匿名变量
      43: iconst_3  ## 从常量池里获取整数3 这里是finally的代码块
      44: istore_0 ## 将值存入第一个整型变量
      45: iload_0 ## 加载第一个整型变量的值
      46: ireturn ## 返回
      47: astore_3 ## 将引用值存入第三个引用变量,这里是异常对象
      48: iconst_3 ## 从常量池里获取整数3 这里是finally的代码块
      49: istore_0
      50: iload_0
      51: ireturn
    Exception table:
       from    to  target type
           0    19    23   Class java/lang/RuntimeException
           0    19    47   any
          23    43    47   any

我们带入Sample1的逻辑,执行的顺序应该是0~16->23->24~40->47,
最后的字节码是

48: iconst_3
49: istore_0
50: iload_0
51: ireturn

因为前面的return其实都是新建了一个匿名对象,所以不影响iload_0;

Sample2

这块字节码的解析就不进行了,直接说调用链0~16->23->24~40->46
最后的字节码是

47: iconst_3
48: istore_0
49: aload_2
50: athrow
public static int finallyTest();
    Code:
       0: iconst_1
       1: istore_0
       2: iload_0
       3: iconst_1
       4: if_icmpne     17
       7: new           #5                  // class java/lang/RuntimeException
      10: dup
      11: ldc           #6                  // String deliberate...
      13: invokespecial #7                  // Method java/lang/RuntimeException."":(Ljava/lang/String;)V
      16: athrow
      17: iload_0
      18: istore_1
      19: iconst_3
      20: istore_0
      21: iload_1
      22: ireturn
      23: astore_1
      24: iconst_2
      25: istore_0
      26: iload_0
      27: iconst_2
      28: if_icmpne     41
      31: new           #5                  // class java/lang/RuntimeException
      34: dup
      35: ldc           #8                  // String deliberate1...
      37: invokespecial #7                  // Method java/lang/RuntimeException."":(Ljava/lang/String;)V
      40: athrow
      41: iconst_3
      42: istore_0
      43: goto          51
      46: astore_2
      47: iconst_3
      48: istore_0
      49: aload_2
      50: athrow
      51: iload_0
      52: ireturn
    Exception table:
       from    to  target type
           0    19    23   Class java/lang/RuntimeException
           0    19    46   any
          23    41    46   any

思考

根据try->catch->finally->return规则,思考以下输出结果:

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

    public static int finallyTest() {
        int a;
        try {
            a = 1;
            if (a == 1) {
                throw new RuntimeException("deliberate...");
            }
            return a;
        } catch (RuntimeException e) {
            a = 2;
            return a;
        } finally {
            a = 3;
        }
    }
}

从上面的字节码可以知道,return一个基础变量的时候,其实是会将该变量值暂存在一个匿名变量里,return的时候,return的是匿名变量,而不是原来的变量;

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/532005.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号