zoukankan      html  css  js  c++  java
  • java-基础-【三】try/catch/finally

    原文地址:

    https://my.oschina.net/bieber/blog/703251

    一、单层的try/catch

    public int test(int a,int b){
            try{
                return a+b;
            }catch (Exception e){
                throw new CustomException();
            }
    }

    通过javap -v查看JVM编译成class字节码之后是如何处理这个try/catch

    public int test(int, int);
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=4, args_size=3
             0: iload_1                          // 将第一个int参数压入队列(第一个入参)
             1: iload_2                          // 将第二个int参数压入队列(第二个入参)
             2: iadd                             //弹出队列中第一个和第二个参数执行相加,并把相加结果压入队列
             3: ireturn                          //弹出队列第一个元素,并return。
             4: astore_3                         //此处是try开始的逻辑
             5: new           #3                 // class com/bieber/demo/CustomException
             8: dup                                
             9: invokespecial #4                 // Method com/bieber/demo/CustomException."<init>":()V
            12: athrow                           //将队列中的第一个元素弹出,并当做异常抛出,到此整个方法体完毕
         Exception table:
             from    to  target type
                 0     3     4   Class java/lang/Exception
         LineNumberTable:
            line 13: 0
            line 14: 4
            line 15: 5
         LocalVariableTable:
            Start  Length  Slot  Name   Signature
                   5       8     3     e   Ljava/lang/Exception;
                   0      13     0  this   Lcom/cainiao/cilogisticservice/ExceptionClass;
                   0      13     1     a   I
                   0      13     2     b   I
         StackMapTable: number_of_entries = 1
              frame_type = 68 /* same_locals_1_stack_item */
              stack = [ class java/lang/Exception ]
    View Code

    上面是test方法JVM编译之后的结果,上面的Code块是整个方法体的内容,而从0-3可以视为是方法体的正常逻辑,4-12可以视为try/catch块,从方法体的指令看,正常情况下执行到3的地方就完毕了,而不会去执行4-12的指令。

    那就得出结论,try/catch代码块在正常逻辑的时候是不会被执行的,于是对于对代码加上try/catch块,并不会影响代码的执行效率,因为根本不会有多余的指令被执行,只有出现异常的时候才会多出执行异常的指令。

    上面的JVM编译的字节码的时候除了Code代码块,还有Exception table代码块,从这个代码块的内容可以看到,包含四列(from,to,target,type),其中fromto表示这个try/catch代码块是从哪开始到哪结束,可以看到上面的try/catch代码块是从Code代码块的0-3,也就是从加载第一个int值到返回结果的代码块,target表示这个try/catch代码块执行逻辑在哪里开始,比如上面的表示从Code中的4开始,也就是astore_3指令开始,直到athrow指令被执行的地方,在Exception table中的一行还有type列,表示是这个异常类型,用于在一个try/catch代码块出现多个catch内容,用于匹配正确的异常类型。

    二、一个try对应多个catch

     public int test(int a,int b){
            try{
                return a+b;
            }catch (Exception e){
                a++;
                throw new CustomException();
            }catch (Throwable t){
                b++;
                throw new CustomException();
            }
        }

    JVM对上面代码编译后的结果:

     public int test(int, int);
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=4, args_size=3
             0: iload_1       
             1: iload_2       
             2: iadd          
             3: ireturn       
             4: astore_3      
             5: iinc          1, 1
             8: new           #3                  // class com/bieber/demo/CustomException
            11: dup           
            12: invokespecial #4                  // Method com/bieber/demo/CustomException."<init>":()V
            15: athrow        
            16: astore_3      
            17: iinc          2, 1
            20: new           #3                  // class com/cainiao/cilogisticservice/CustomException
            23: dup           
            24: invokespecial #4                  // Method com/cainiao/cilogisticservice/CustomException."<init>":()V
            27: athrow        
          Exception table:
             from    to  target type
                 0     3     4   Class java/lang/Exception
                 0     3    16   Class java/lang/Throwable
          LineNumberTable:
            line 13: 0
            line 14: 4
            line 15: 5
            line 16: 8
            line 17: 16
            line 18: 17
            line 19: 20
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                   5      11     3     e   Ljava/lang/Exception;
                  17      11     3     t   Ljava/lang/Throwable;
                   0      28     0  this   Lcom/cainiao/cilogisticservice/ExceptionClass;
                   0      28     1     a   I
                   0      28     2     b   I
          StackMapTable: number_of_entries = 2
               frame_type = 68 /* same_locals_1_stack_item */
              stack = [ class java/lang/Exception ]
               frame_type = 75 /* same_locals_1_stack_item */
              stack = [ class java/lang/Throwable ]
    View Code

    和上面的内容对比一下会发现,在Code中多出了一段astore_3/athrow块,并且在Exception table中多了一行,想想通过上面的解释,对这个多出的一行的目的应该都知道是用来什么的,由于我在catch中成了throw之外,还多了一个++的操作,可以看到在astore_3/athrow块中多出了iinc指令,所以可以理解,try/catch在JVM中对应的是一个子代码块,在条件满足(出现匹配的catch异常)的时候会被执行。

    下面我整理一下当出现异常的(这里说的是有try/catch的异常)JVM处理流程:

    1、在try/catch出现异常
    2、JVM会去`Exception table`查找匹配的异常类型
    3、假设匹配上了,那么读取from,to,target,获取待执行的`try/catch`块的指令(具体是否抛出,看是否有athrow指令)。

    三、try/finally块的执行处理

    public int test(int a,int b){
            try{
                return a+b;
            }catch (Exception e){
                a++;
                throw new CustomException();
            }finally {
                b++;
            }
        }

    JVM编译后的指令:

    public int test(int, int);
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=5, args_size=3
             0: iload_1       
             1: iload_2       
             2: iadd          
             3: istore_3                         //将栈顶的元素存储局部变量数组的第三个位置
             4: iinc          2, 1               //执行b++
             7: iload_3                          //把局部变量第三个位置的数值压入栈顶
             8: ireturn                          //弹出栈顶,并且返回
             9: astore_3      
            10: iinc          1, 1               //a++
            13: new           #3                  // class com/bieber/demo/CustomException
            16: dup           
            17: invokespecial #4                  // Method com/bieber/demo/CustomException."<init>":()V
            20: athrow        
            21: astore        4
            23: iinc          2, 1                //b++
            26: aload         4
            28: athrow        
          Exception table:
             from    to  target type
                 0     4     9   Class java/lang/Exception
                 0     4    21   any
                 9    23    21   any
          LineNumberTable:
            line 13: 0
            line 18: 4
            line 14: 9
            line 15: 10
            line 16: 13
            line 18: 21
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                  10      11     3     e   Ljava/lang/Exception;
                   0      29     0  this   Lcom/cainiao/cilogisticservice/ExceptionClass;
                   0      29     1     a   I
                   0      29     2     b   I
          StackMapTable: number_of_entries = 2
               frame_type = 73 /* same_locals_1_stack_item */
              stack = [ class java/lang/Exception ]
               frame_type = 75 /* same_locals_1_stack_item */
              stack = [ class java/lang/Throwable ]
    View Code

    通过上面的代码,你会发现在Exception table都出了两行,其实我们只是在代码中只有一个try/catch块,而这里出现了三个,那么另外两个是做什么的呢?可以看到多出的两行的type都是any,这里的any表示的是任何异常类型,多出的第一行,是从0-4,表示0-4之间的指令出现异常,会从21的指令开始执行,发现执行的是b++(finally)的内容,多出的第二行是9-23,表示9-23之间的指令被执行的过程中出现异常也会从21行开始执行(也是执行finally的内容),而9-23其实是catch的代码逻辑。上面均是出现了异常会触发finally的代码执行,正常情况下会发现4的位置执行了finally的内容,然后再执行ireturn指令,这里可以得出,JVM处理finally其实是对于正常的指令队列增加了finally代码块的指令,以及对异常中添加了finally代码块的指令,这也就导致了fianlly在任何地方都可以被执行,其实就是冗余了指令队列(其实思想比较简单)。

  • 相关阅读:
    sql server 镜像操作
    微信测试公众号的创见以及菜单创建
    linux安装redis步骤
    Mysql 查询表字段数量
    linux 链接mysql并覆盖数据
    linux (centos)增删改查用户命令
    CentOS修改用户密码方法
    https原理及其中所包含的对称加密、非对称加密、数字证书、数字签名
    com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. 问题解决方法
    设计模式(三):模板方法模式
  • 原文地址:https://www.cnblogs.com/bjlhx/p/6761099.html
Copyright © 2011-2022 走看看