try-catch-finally字节码分析及其常见问题最全总结——Java进阶

原文链接:try-catch-finally字节码实例探究 | 代码段小站 ,欢迎访问我的博客

本文使用Idea的jclasslib插件查看字节码。本文全程自言自语,请勿自行代入。

概述

java是怎么处理try-catch-finally的?

需要了解的是,在class字节码中的属性表中,存在code属性,它用于存放各方法的字节码、属性等。其中就包括exception_info,即异常表,它记录了当一个异常发生后,应跳转到哪一行继续执行,而finally里面的代码块编译成字节码后则是被复制成许多份分别附在try和各catch块的后面。不了解这个原理没有关系,下面,我会从一个最简单的例子入手,带你走进try-catch-finally的世界。

这篇文章,我们就通过一些实例来看看,java中的try-catch-finally引申出的一些问题。

普通的例子

普通中的普通例子

我们先来一个普通的例子

public static void normal(){
   
    try {
   
        System.out.print("try-");
    }catch (Exception e){
   
        System.out.print("catch");
    }finally {
   
        System.out.print("finally");
    }
}

这个相信大家都知道是输出try-finally,因为没有异常出现,那么它的字节码是:

 0 getstatic #4 <java/lang/System.out>
 3 ldc #5 <try->
 5 invokevirtual #6 <java/io/PrintStream.print>
---------------- 上面这部分输出"try-"-----------------
 8 getstatic #4 <java/lang/System.out>
11 ldc #7 <finally>
13 invokevirtual #6 <java/io/PrintStream.print>
---------------- 上面这部分输出"finally"--------------
16 goto 50 (+34)
-----------正常流程,跳转到50行直接return--------------
19 astore_0
20 getstatic #4 <java/lang/System.out>
23 ldc #8 <catch>
25 invokevirtual #6 <java/io/PrintStream.print>
-----上面这部分输出"catch",astore_0存入的是异常信息-----
28 getstatic #4 <java/lang/System.out>
31 ldc #7 <finally>
33 invokevirtual #6 <java/io/PrintStream.print>
36 goto 50 (+14)
-----注意上面这部分也是输出"finally",和之前某部分一样----
39 astore_1
40 getstatic #4 <java/lang/System.out>
43 ldc #7 <finally>
45 invokevirtual #6 <java/io/PrintStream.print>
48 aload_1
49 athrow
-----注意上面这部分也是输出"finally",但抛出了一个异常----
50 return

我们看看异常表:

如何解读:

  • 0-8行(不包括8)的语句出现异常(类型为Exception,是我们catch的异常类型),交由19行处理(catch代码块),我们注意到28行执行完catch代码块后,就执行finally代码块。
  • 0-8行的语句出现异常(类型为any,代表任何异常),交由39行处理,为什么这里会有这一项呢?是因为我们定义了finally,如果在try中出现了我们没有catch的异常类型,就可能会出现finally中的代码没有执行的情况,所以为了防止finally中的代码不执行,编译器会自动为我们暂时store这个异常信息(对应39行),执行完finally语句块后再抛出(对应49行)
  • 19-28行的语句出现异常(类型为any,代表任何异常),交由39行处理。为什么这里会有这一项呢?原因和上面一样,如果执行catch代码块又出现了异常,也要保证finally代码块的执行。

普通例子举一反三

有了上面这个例子,我们就来思考一下,如果没有finally代码块,字节码会是什么样子的呢?

public static void normal(){
   
    try {
   
        System.out.print("try-");
    }catch (Exception e){
   
        System.out.print("catch");
    }
}

首先能想到的是,正常流程执行完try中的内容就应该直接返回。而出现异常就应该跳转至中间一段用于处理异常的代码块。因为没有finally代码块,应该也不会有那么多冗余代码块被复制。

验证:

 0 getstatic #4 <java/lang/System.out>
 3 ldc #5 <try->
 5 invokevirtual #6 <java/io/PrintStream.print>
----------上面输出"try-"-------------------------
 8 goto 20 (+
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值