从字节码角度看try catch finally处理过程

简介: 本文通过分析一段示例代码的字节码指令,讨论异常流程的处理。

本文通过分析一段示例代码的字节码指令,讨论异常流程的处理。

 

一  示例代码

代码如下,在讨论异常处理流程前,不妨先思考一下,在抛出异常和不抛出异常时,返回的结果是多少?是3,是4,还是5?为什么?


    public int test() {
        int x ;
        // int y = 0 ;
        try {
            x = 3;
            // int z = x/y ;
            return x;
        } catch (Exception e) {
            x = 4;
            return x;
        } finally {
            x = 5;
        }
    }
 

二  字节码指令介绍

简单介绍一下示例中使用到的指令,更多指令见虚拟机指令集。

指令

意义

iload_n(0~3)

将局部变量表中第n个槽的(int)变量推送到操作数栈。

n大于3时,指令改为iload n,例如iload 4表示将第4个槽的变量存到操作数栈中

istore_n(0~3)

将操作数栈顶的值弹出存到局部变量表的第n个槽中。

n大于3时,指令改为istore n,例如istore 5表示将操作数栈中的值弹出并存储到局部变量表的第5个槽中

astore_n(0~3)

将栈顶引用类型的值存到局部变量表中的第n个槽中

n大于3时,指令改为 astore n

iconst_n (−1~5)

将常量n入栈

n<-1或者n>5时,指令改为bipush n

bipush n

将一个常量入栈

 

三  编译后的字节码指令

上面的示例代码,不论是否抛出异常,返回结果均不会是5,接下来我们以不抛出异常时编译出来的的字节码指令讨论一下这个问题。

1   字节码分析

以下为编译成字节码以后的代码,以及每一步的意义。

  public int test();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=5, args_size=1
         0: iconst_3            // 对应try块中的x=3,并将3入栈(操作数栈)
         1: istore_1            // 将栈顶元素(3)弹出并存储到局部变量表第1个slot中
         2: iload_1             // 加载局部变量表中第1个slot的值(3)到栈栈顶
         3: istore        4    // 将栈顶的元素(3)存储到局部变量表第4个slot中
         5: iconst_5            // 对应于finally块中x=5,并将5入栈
         6: istore_1            // 将栈顶元素(5)弹出并存储到局部变量表第1个slot中
         7: iload         4    // 加载局部变量表第4个slot的值(3)到栈中
         9: ireturn             // 弹出栈顶元素并返回
        10: astore_2            // 将栈顶引用元素(exception弹出并存储在局部变量表第2个slot中
        11: iconst_4            // 对应catch块中的x=4,并将4入栈
        12: istore_1            // 将栈顶元素(4)弹出并存储在局部变量表第1个slot中
        13: iload_1             // 将局部变量表第1个slot元素(4)加载到栈顶
        14: istore        4    // 将栈顶元素(4)弹出并存储在局部变量表第4个slot中
        16: iconst_5            // 对应于finally块中x=5,并将5入栈
        17: istore_1            // 将栈顶元素(5)弹出并存储到局部变量表第1个slot中
        18: iload         4    // 加载局部变量表第4个slot的值(4)到栈中
        20: ireturn             // 弹出栈顶元素并返回
        21: astore_3            // 如果出现不属于Exception或其子类会执行此指令,将栈顶元素(Exception)弹出并存储到局部变量表第3个slot中
        22: iconst_5            // 对应于finally块中x=5,并将5入栈
        23: istore_1            // 将栈顶元素(5)弹出并存储到局部变量表第1个slot中
        24: aload_3             // 将局部变量表中第3个slot的值(Exception)加到栈顶
        25: athrow              // 弹出栈顶元素并抛出异常
      Exception table:
         from   to  target type
             0     5   10   Classjava/lang/Exception    //如果try中出现Exception异常(或其子类),那么跳转转到catch语句块处理
             0     5   21   any                          //如果try语句快出现了不属于Exception的异常,那么进入finally语句块处理
            10    16   21   any                          //如果catch出现任何异常,那么进入finally语句块处理


 

2   输出结果分析

通过字节码指令分析,我们可以看到ireturn指令返回的都是从局部变量表第4个slot中取出的值,而此值在执行finally之前已经存储好了,并且在执行finally代码块之间没有做任何修改,所以示例代码不会返回5,如果抛出异常返回4,不抛出异常返回3;




 

相关文章
|
6月前
|
Java UED
【JavaSE专栏68】异常的捕获和处理,try-catch-finally高效解决异常处理问题
【JavaSE专栏68】异常的捕获和处理,try-catch-finally高效解决异常处理问题
|
4月前
|
Java
Java异常处理:解释一下异常的传播机制。
Java异常处理:解释一下异常的传播机制。
49 1
|
10月前
Catch块异常多类抓取
Catch块异常多类抓取
32 0
|
11月前
|
存储 Java
高并发编程-捕获线程运行时的异常 + 获取调用链
高并发编程-捕获线程运行时的异常 + 获取调用链
67 0
|
Java
Java异常——处理机制Try-catch-finally
Java异常——处理机制Try-catch-finally
152 0
如何实现不论是否发生异常都必须执行 使用关键字finally finally: 我们有一些场景 需要保证代码无论是否异常都要执行 需要放到finally里
如何实现不论是否发生异常都必须执行 使用关键字finally finally: 我们有一些场景 需要保证代码无论是否异常都要执行 需要放到finally里
|
监控 Java 编译器
JVM 异常表及 try-catch-finally 字节码分析
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 作为一个“有经验”的 Java 工程师,你一定知道什么是try-catch-finally代码块。
JVM 异常表及 try-catch-finally 字节码分析
|
Java 编译器 开发者
一文了解java异常机制
一文了解java异常机制1.异常的概述1.1什么是异常?异常:程序在运行过程中发生由于外部问题导致的程序异常事件,发生的异常会中断程序的运行。(在Java等面向对象的编程语言中)异常本身是一个对象,产生异常就是产生了一个异常对象。
5327 0
|
Java 程序员 安全
Java异常与处理机制
Java异常与处理机制Java的异常层次体系 Java的所有异常对象都派生自Throwable类,下层有两个分支:error和exception。 Error分支描述Java运行时系统内部错误或资源耗尽错误,遇到派生自Error的错误,程序除了通告给用户并尽量安全退出外也无能为力。
804 0
Java异常被抛出或被捕获之后,代码是否继续执行的问题
在写程序的时候,我们经常被教导,要对异常的信息进行处理,哪里该抛出异常。但是,更多的时候,我们只是模仿异常的抛出,却不知道为什么要这样抛异常(被catch了?被向上抛了?后面的代码是否执行了?)。 接下来,我就简单的说一下异常抛出后的代码执行问题。
7040 1