Java基础之try catch finally的原理

先看一段代码

public static int test() {
        int i = 0;
        try {
            System.out.println("业务执行");         // 标记1
            i = 1 / 0;
            System.out.println("业务执行完成");
            i++;                                  // 标记2
            return i;
        } catch (Exception e) {
            System.out.println("捕捉异常");        //  标记3
            i++;                                 //  标记4
            return i;
        } finally {
            System.out.println("释放资源");       //  标记5
            i++;                                //  标记6
            return i;
        }
    }

带着问题找答案

问题1:try {} 里面的代码没有抛出异常,正确的执行了 try {} 代码中的 return 指令,finally {} 中的代码会被执行,那底部的执行原理是怎样的呢。

问题2:try {} 里面的代码抛出了异常,接着会执行 catch {} 中的代码且 catch {} 中的代码没有抛出异常正确的执行了 return 指令,执行 finally 中的代码也会被执行,那底部的执行原理是怎样的呢。

问题3:try {} 里面的代码抛出了异常,接着会执行 catch {} 中的代码且 catch {} 中的代码也抛出了异常,执行 finally 中的代码也会被执行,那底部的执行原理是怎样的呢。

以上三个问题总结如下图

通过javap查看class文件字节码,命令为javap -c -s -v -l TestMain.class

这里只是帖出了 test 方法有关的字节码,

重点(看懂这三点,也就明白了 try catch finally 的底层原理)

  • 绿色表示 try {} 中的代码,红色表示 catch {} 中的代码,蓝色表示 finally {} 中的代码。
  • finally {} 中代码的字节码别编织到了三个地方(看懂这一点,也就明白了 try catch finally 的底层原理)
  • Exception table,列表中记录了从字节码 from 到字节码 to,如果执行期间出现异常 代码分支应该如何走

字节码如下

public static int test();

descriptor: ()

flags: ACC_PUBLIC, ACC_STATIC

Code:

stack=2, locals=4, args_size=0

0: iconst_0

1: istore_0

------实际运行中 try {} 中的字节码 begin --------

2: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

5: ldc #3 // String 业务执行

7: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

10: iconst_1

11: iconst_0

12: idiv

13: istore_0

14: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

17: ldc #5 // String 业务执行完成

19: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

22: iinc 0, 1

25: iload_0

26: istore_1

27: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

30: ldc #6 // String 释放资源

32: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

35: iinc 0, 1

38: iload_0

39: ireturn // 对应着代码中的标记 2

------实际运行中 try {} 中的字节码 end----------

------实际运行中 catch {} 中的字节码 begin --------

40: astore_1

41: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

44: ldc #8 // String 捕捉异常

46: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

49: iinc 0, 1

52: iload_0

53: istore_2

54: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

57: ldc #6 // String 释放资源

59: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

62: iinc 0, 1

65: iload_0

66: ireturn // 对应着代码中的标记 4

------实际运行中 catch {} 中的字节码 end --------

------实际运行中 finally {} 中的字节码 begin --------

67: astore_3

68: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

71: ldc #6 // String 释放资源

73: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

76: iinc 0, 1

79: iload_0

80: ireturn // 对应着代码中的标记 6

------实际运行中 finally {} 中的字节码 end --------

Exception table:

from to target type

2 27 40 Class java/lang/Exception // 2 到 26 之间的代码是 try {} 中的代码,运行期间如果抛出 Exception 则跳转到 40,也就是 catch {} 中代码的第一行

2 27 67 any // 2 到 26 之间的代码是 try {} 中的代码,运行期间没有抛出异常则跳转到 67 也就是 finally {} 中代码的第一行

40 54 67 any // 40 到 53 之间的代码是 catch {} 中的代码,运行期间如果抛出异常则跳转到 67 也就是 finally {} 中代码的第一行

参考文章

Java基础之try catch finally的原理 - 掘金

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值