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 ]

上面是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 ]

和上面的内容对比一下会发现,在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 ]

通过上面的代码,你会发现在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在任何地方都可以被执行,其实就是冗余了指令队列(其实思想比较简单)。

时间: 2024-09-30 01:52:00

java-基础-【三】try/catch/finally的相关文章

Java面试题总结之Java基础(三)

1.JAVA 语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try 块中可以抛出异常吗? 答:Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口.在Java 中,每个异常都是一个对象,它是Throwable 类或其它子类的实例.当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理.Java 的异常处理是通过5 个关键词来实现的:try.ca

java 基础三

1 运算符 1.1  比较运算符 比较运算符的结果都是boolean类型,也即是要么是true,要么是false. 比较运算符"=="不能写成"=". > package java003; /** * 2017/8/31. * 说明: */ public class OperateDemo { public static void main(String[] args) { int a = 3; int b = 7; System.out.print(a>

java基础三种循环的使用及区别

摘要:Java新人初学时自己的一些理解,大神们路过勿喷,有什么说的不对不足的地方希望能给予指点指点,如果觉得可以的话,希望可以点一个赞,嘿嘿,在这里先谢了.在这里我主要说的是初学时用到的Java三个循环体的用法及区别:for  while和do while在什么时候会使程序代码更方便简洁: 一.for循环体,这个在我以后写程序代码都是比较长用的一个循环体之一,for循环主要多数用到我们已经知道循环次数的循环程序中. 表达式:for(初始化:布尔表达式:更新){ 程序代码....... } for

Java基础(三)-final关键字分析

今天来谈谈final关键字的作用, 虽然有很多博文关于final进行了很深的研究,但还是要去记录下谈谈自己的见解加深下印象.下面直接进入主题: 一.final关键字的作用 1.被final修饰的类不能被继承. 这一点应该很多人都知道也遇到过,经典案例就是java.lang.String类 还有一些常见的类也是被final所修饰的,如下: 基本类型对应的包装类型(如java.lang.Integer.java.lang.Long等).字符相关类(java.lang.StringBuilder.ja

Java基础(三)

流程概述 概念:流程是指程序步骤执行的先后顺序,先做什么,后做什么. 分类: 1. 顺序结构:从上到下,从前向后,顺序执行. 2. 选择结构:执行路线分叉,做这个,或者做那个,也叫分支结构. 3. 循环结构:重复做一些事情. 顺序结构 没有特定的语法结构. 写在前面的先执行,写在后面的后执行. 选择结构 Java中主要通过if语句来实现选择分支流程,if语句的格式有常用的三种: l  单if语句:执行某些步骤,或者不执行它们. l  标准的if-else语句:在2套步骤方案中选择一种执行. l 

java基础三

1,多线程编程: 线程和进程的区别:进程需要独立的内存空间,进程关闭那么线程关闭:而线程可以共享内存和资源,线程关闭进程不关闭. Thread类和Runnable类,线程的创建:1,继承Thread类实例化一个Thread,然后重写Thread的run方法,然后调用start方法启动线程:2,实现一个Runnable接口,创建一个Runnable类并实例化并将实例传入Thread类的构造器内,再调用Thread类实例的start方法: 线程的优先级(setPriority):数字越大优权越高,默

java基础三 [深入多态,接口和多态](阅读Head First Java记录)

抽象类和抽象方法 1.抽象类的声明方法,在前面加上抽象类的关键词abstract abstract class canine extends animal{ public void roam(){} } 抽象类除了被继承过之外,是没有用途,没有值,没有目的.类中的方法可以当做子类的合约内容,合约是对其他程序的承诺协议 抽象类中可以带有抽象和非抽象的方法 如果类中有抽象方法,则类必定标识为抽象的. 2.抽象的方法没有实体 (因为方法中的程序代码没有意义.抽象类需要被extend过有意义,抽象方法一

重学JAVA基础(三):动态代理

1.接口 public interface Hello { public void sayHello(); } 2.实例类 public class Hello2 { public void sayHello() { System.out.println("hello world2!"); } } public class Hello3 extends Hello2{ } public class HelloImpl implements Hello{ @Override public

java基础知识文章汇总

将之前的所有关于Java基础知识的随笔,整理成质量较高的十几篇随笔,几乎是好几篇比较零散的随笔合成现在的一篇,自认为还不错. java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序的深入解析 java基础(五) String性质深入解析 java基础(六) switch语句的深入解析 java基础(七) java四种访问权限 java基础(八) 深入解析常量池与装拆箱机制 java

Java基础总结(三)

一.开始的唠叨 Java中有一大块的内容是组件及事件处理,一刷Java时是为了写Web,前端有Html没学这部分内容.二刷时已经在做Android了,前端有自带的组件,依然跳过. 我也不建议道友去学习这部分内容,现在真的有人用Java写C/S吗? 二.学习笔记 (一)输入输出流 1.流:输入流.输出流是针对程序而言的. 所有输入流都是InputStream(字节输入流)或Reader(字符输入流)的子类: 所有输出流都是OutputStream(字节输出流)或Writer(字符输出流)的子类:(