java异常处理(二)—从字节码层面看throw关键字及try...catch...finally的实现

代码已上传gitee:https://gitee.com/shang_jun_shu/springboot-exception-jsr303.git
其他系列博客
Java异常处理(一)一异常处理流程
java异常处理(三)—Springboot全局异常处理(@ControllerAdvice和ErrorController)
java异常处理(四)—还在用if判断校验参数?试试SpringBoot全局异常+JSR303校验吧!

一、整体概括

在这里插入图片描述
java虚拟机对于异常的情况有两个处理方式,一个是抛出异常,一个是处理异常;

抛出异常中显式抛出异常(throw关键字)是由athrow指令实现,除此之外java虚拟机规范还规定了许多运行时异常会在其他java虚拟机指令检测到异常状况时自动抛出,例如除法运算,除数为0情况,虚拟机会在idiv或ldiv指令中抛出ArithmeticException异常。

另一个处理异常的方式,即catch语块则通过异常表实现

二、javap反编译字节码

举个例子,使用javap反编译DivException的class文件
在这里插入图片描述

三、throw显式抛出异常

public class DivException {
    void div(int num){
        if(num==0){
            throw new ArithmeticException("除数为0");
        }
    }
}

使用javap反编译字节码文件结果

Compiled from "DivException.java"
public class com.thinkcoder.exceptionjvm.DivException {
  public com.thinkcoder.exceptionjvm.DivException();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  void div(int);
    Code:
       0: iload_1
       1: ifne          14
       4: new           #2                  // class java/lang/ArithmeticException
       7: dup
       8: ldc           #3                  // String 除数为0
      10: invokespecial #4                  // Method java/lang/ArithmeticException."<init>":(Ljava/lang/String;)V
      13: athrow
      14: return
}

看反编译的字节码文件的13行,throw关键字是通过athrow指令实现的

四、jvm如何执行try…catch…finally

首先再来说下这三个语块的作用:

  • try:捕获异常
  • catch:处理异常
  • finally:最后执行的代码

4.1异常表及异常处理器

4.1.1 什么是异常表?

异常表存在于Code属性表中,而Java程序方法体里面代码经过编译后,最终变为字节码指令存储在Code属性中,那么有关如何处理异常的指令存储在异常表中。值得注意的是,异常表对于Code属性不是必须存在,也就是说并不是每个方法都有对应的异常表存在

4.1.2异常表结构?

Exception table:
   from    to  target type
       0     4     9   Class java/lang/ArithmeticException
       0     4    19   any
       9    14    19   any
      19    21    19   any

异常表由异常处理器组成,上述异常表由4条异常处理器组成;

  • 异常处理器由from指针、to指针、target指针,以及所捕获的异常类型所构成(type)
  • 三个指针的数值是字节码的行数,可以直接定位字节码,"行数"更确切的说是指的是,字节码相对于方法体开始的偏移量
  • from指针到to指针(不含该指针的行数),标识了该异常处理器监控字节码的范围
  • target指针,指向异常处理器的起始位置。如catch代码块的起始位置
  • type:捕获的异常类型,如Exception

4.1.3异常表作用?

从结构可以看出来,异常表实现了java中try…catch…finally的异常处理,对实现finally,jdk从1.7开始已经完全抛弃jsr和ret指令,也是使用异常表实现

4.2举个例子:

从例子中看如何实现try…catch…finally

java代码如下

public class DivException {
    void div(int num){
        int a;
        try{
            a = 5/num;
        }catch (ArithmeticException e){
            e.printStackTrace();
        }finally {
            a=1;
        }
    }
}

反编译class文件如下:

public class com.thinkcoder.exceptionjvm.DivException {
  public com.thinkcoder.exceptionjvm.DivException();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  void div(int);
    Code:
       0: iconst_5                 //将常数值5压入栈顶
       1: iload_1                  //将局部变量槽第一个值即m的值复制到操作数栈顶
       2: idiv                     //将栈顶两数值相除并将结果压入栈顶
       3: istore_2                 //将操作数栈顶数值即运算结果,存入到第2个局部变量槽中
       4: iconst_1                 //将常数值1压入栈顶
       5: istore_2                 //将操作数栈顶数值存入到第2个局部变量槽中
       6: goto          26         //执行偏移量26的指令
       9: astore_3                 //将操作数栈栈顶数值(异常实例e引用,此引用指向堆内存异常实例)存入到第3个局部变量槽中
      10: aload_3                  //将第3个局部变量槽即e引用复制到操作数栈顶
      11: invokevirtual #3         //调用实例e的printStackTrace方法   Method java/lang/ArithmeticException.printStackTrace:()V
      14: iconst_1                 //将常数值1压入操作数栈顶
      15: istore_2                 //将操作数栈顶数值存入到第2个局部变量槽中
      16: goto          26         //执行偏移量26的指令
      19: astore        4          //出现不属于ArithmeticException异常走这里,猜测是Throw接口类型的实例,将该实例存入到第4个局部变量槽中
      21: iconst_1                 //将常数值1压入栈顶
      22: istore_2                 //将操作数栈顶数值存入到第2个局部变量槽中
      23: aload         4          //将Throw实例e复制到操作数栈顶
      25: athrow                   //抛出去
      26: return                   //方法返回
    Exception table:
       from    to  target type
           0     4     9   Class java/lang/ArithmeticException
           0     4    19   any
           9    14    19   any
          19    21    19   any
}

字节码与java代码对应如下
在这里插入图片描述

4.3如何实现try

  • 带有try…catch的方法中,方法会携带一个异常表
  • 异常表中每个条目都是一个异常处理器
  • 触发异常时,JVM会遍历异常表,比较触发异常行数(方法开始的偏移量)是否在异常处理器from指针到to指针范围内
  • 范围匹配后,会比较异常类型和异常处理器中的type是否相同
  • 类型匹配后,会跳转到target指针所指向的字节码(catch代码块开始位置)
  • 如果没有匹配到异常处理器,会弹出当前方法对应的Java栈帧,并对调用者重复操作

4.4如何实现catch

如果try中的字节码在from指针和to指针范围内且异常类匹配,则执行target指针指向的字节码,此时执行catch块的代码块

4.5如何实现finally

我们知道finally是在try…catch…finally块中,除了极端情况发生最后都要执行的代码,那么jvm是如何实现这一现象呢?

就是将finally块的字节码复制了三份,对照上图可以发现,这三份代码分别放在了不同位置

  • try块后
  • catch块
  • 位于异常执行路径:如果try中有异常但没有被catch捕获,或者catch又抛异常,那么就执行最终的finally代码

这三个位置保证了finally的代码最终要被执行

参考博客

https://www.cnblogs.com/hulianwangjiagoushi/p/10901257.html

https://blog.csdn.net/feather_wch/article/details/82630303

创作不易,觉得有帮助的,来个三连吧
在这里插入图片描述

商俊帅 CSDN认证博客专家 Java csdn博客专家
代码路上的小学生,主要涉及有Java、Spring、分布式、微服务等,热爱技术,乐于分享,一起成长,遇见未知的自己
相关推荐
<p> <strong><span style="font-size:20px;color:#FF0000;">本课程主要针对计算机相关专业正在做毕设学生与需要项目实战练习Java学习者</span></strong> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">1. 包含:<span style="color:#FFFF00;background-color:#FF0000;">项目源码、</span><span style="color:#FFFF00;background-color:#FF0000;">项目文档、数据库脚本、软件工具</span>等所有资料</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">2. 手把手带你零开始部署运行本套系统</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">3. 该项目附带源码资料可作为毕设使用</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">4. 提供技术答疑和远程协助指导</span></strong></span><strong><span style="font-size:18px;"></span></strong> </p> <p> <br /> </p> <p> <span style="font-size:18px;"><strong>项目运行截图:</strong></span> </p> <p> <strong><span style="font-size:18px;">1系统登陆界面</span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241015433522.png" alt="" /><br /> </span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">2学生模块</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241015575966.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">3教师模块</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016127898.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">4系统管理员</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016281177.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016369884.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><br /> </span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">更多Java毕设项目请关注我毕设系列课程 <a href="https://edu.csdn.net/lecturer/2104">https://edu.csdn.net/lecturer/2104</a></span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><br /> </span></strong> </p>
<p> 课程演示环境:Windows10  </p> <p> 需要学习<span>Ubuntus</span>系统<span>YOLOv4-tiny</span>同学请前往《<span>YOLOv4-tiny</span>目标检测实战:训练自己数据集》 <span></span> </p> <p> <span> </span> </p> <p> <span style="color:#E53333;">YOLOv4-tiny</span><span style="color:#E53333;">来了!速度大幅提升!</span><span></span> </p> <p> <span> </span> </p> <p> <span>YOLOv4-tiny</span>在<span>COCO</span>上性能可达到:<span>40.2% AP50, 371 FPS (GTX 1080 Ti)</span>。相较于<span>YOLOv3-tiny</span>,<span>AP</span>和<span>FPS</span>性能有巨大提升。并且,<span>YOLOv4-tiny</span>权重文件只有<span>23MB</span>,适合在移动端、嵌入式设备、边缘计算设备上部署。<span></span> </p> <p> <span> </span> </p> <p> 本课程将手把手地教大家使用<span>labelImg</span>标注和使用<span>YOLOv4-tiny</span>训练自己数据集。课程实战分为两个项目:单目标检测足球目标检测和多目标检测足球和梅西同时检测。<span></span> </p> <p> <span> </span> </p> <p> 本课程<span>YOLOv4-tiny</span>使用<span>AlexAB/darknet</span>,在<span>Windows10</span>系统上做项目演示。包括:<span>YOLOv4-tiny</span>网络结构、安装<span>YOLOv4-tiny</span>、标注自己数据集、整理自己数据集、修改配置文件、训练自己数据集、测试训练出网络模型、性能统计<span>(mAP</span>计算<span>)</span>和先验框聚类分析。 <span> </span> </p> <p> <span> </span> </p> <p> 除本课程《<span>Windows</span>版<span>YOLOv4-tiny</span>目标检测实战:训练自己数据集》外,本人推出了有关<span>YOLOv4</span>目标检测系列课程。请持续关注该系列其它视频课程,包括:<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:训练自己数据集》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:人脸口罩佩戴识别》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:中国交通标志识别》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测:原理与源码解析》<span></span> </p> <p> <span> <img alt="" src="https://img-bss.csdnimg.cn/202007061503586145.jpg" /></span> </p> <p> <span><img alt="" src="https://img-bss.csdnimg.cn/202007061504169339.jpg" /><br /> </span> </p>
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页