原文地址:

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在任何地方都可以被执行,其实就是冗余了指令队列(其实思想比较简单)。

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

  1. Java基础系列 - try...catch...finally

    package com.test6; import java.io.FileReader; import java.io.IOException; /** * try...catch...finall ...

  2. Java 基础三、接口与内部类

    1.   在Java程序语言中,接口是对类的一种描述.例如Arrays类中sort方法声明可以对对象进行排序,但前提是对象所属的类必须实现Comparable接口. public interface ...

  3. java基础(三):反射、反序列化破解单列模式和解决方式

    单例模式指的是一个类只有一个对象,通过一些措施达到达到这个目的.但是反射和反序列化可以获得多个不同的对象. 先简单的认识一下单例模式 一:单例模式 通过私有构造器,声明一个该类的静态对象成员,提供一个 ...

  4. java基础(三) 加强型for循环与Iterator

    引言   从JDK1.5起,增加了加强型的for循环语法,也被称为 "for-Each 循环".加强型循环在操作数组与集合方面增加了很大的方便性.那么,加强型for循环是怎么解析的 ...

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

    1.JAVA 语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try 块中可以抛出异常吗? 答:Java 通过面向对象的方法进行异常处理, ...

  6. java基础(三)

    1.枚举类,使用enum定义的枚举类默认继承java.lang.Enum,而不是Object类.枚举类的所有实例必须在枚举类中显示列出,否则这个枚举类永远都不能产生实例.相关内容较多,需要后续继续跟进 ...

  7. java 基础三 下雪

    通过repaint()方法进行重画. import javax.swing.JFrame; import javax.swing.JPanel; import java.awt.Graphics; p ...

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

    摘要:Java新人初学时自己的一些理解,大神们路过勿喷,有什么说的不对不足的地方希望能给予指点指点,如果觉得可以的话,希望可以点一个赞,嘿嘿,在这里先谢了.在这里我主要说的是初学时用到的Java三个循 ...

  9. java 基础三

    1 运算符 1.1  比较运算符 比较运算符的结果都是boolean类型,也即是要么是true,要么是false. 比较运算符"=="不能写成"=". > ...

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

    今天来谈谈final关键字的作用, 虽然有很多博文关于final进行了很深的研究,但还是要去记录下谈谈自己的见解加深下印象.下面直接进入主题: 一.final关键字的作用 1.被final修饰的类不能 ...

随机推荐

  1. 建造者模式(build pattern)-------创造型模式

    将一个复杂对象的构建与它的标示分离,使得同样的构建过程可以创建不同的标示. 建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程分离,客户端无须知道复杂对象的内 ...

  2. Java 9的日期时间格式化趋近Unicode区域设置标准

        1.JDK-8148947,DataTimeFormatter的模式字母“g”:正如在LDML中定义的,字母“g”指代一个“简化儒略日期”,简化儒略日期与正常儒略日期的差别在于:(1)简化儒略 ...

  3. 【SSH进阶之路】Hibernate映射——一对一双向关联映射(六)

    上篇博文[SSH进阶之路]Hibernate映射--一对一单向关联映射(五),我们介绍了一对一的单向关联映射,单向是指仅仅能从人(Person)这端载入身份证端(IdCard),可是反过来.不能从身份 ...

  4. php开n次方

    php有开平方函数 sqrt,但没开n次方的函数 网上用根据什么数字原理,可用次方(pow)弄开方,格式为:pow(number, 1/ 开方数) 例如: 4的开平方,可以写成 pow(4, 1/2) ...

  5. ASP代码审计学习笔记-1.SQL注入

    ASP注入漏洞 一.SQL注入的原因 按照参数形式:数字型/字符型/搜索型 1.数字型sql查询 sql注入原因: ID=49 这类注入的参数是数字型,SQL语句原貌大致如下: id=request. ...

  6. java生成webservice方法

    参考: https://note.youdao.com/ynoteshare1/index.html?id=c10324bb3b794baece3d2ae9faadc5c1&type=note

  7. HTML 解析

    xml,json都有大量的库来解析,我们如何解析html呢? TFHpple是一个小型的封装,可以用来解析html,它是对libxml的封装,语法是xpath.今天我看到一个直接用libxml来解析h ...

  8. PHP的函数-----生成随机数、日期时间函数

    常用的函数 [1]   生成随机数 rand(); 例子: echo rand(); 显示结果: 当刷新时,会有不同的数,默认生成随机数.生成随机数不能控制范围. 如果,想要控制在范围之内,就用: e ...

  9. Android Training - 管理应用的内存

    http://hukai.me/android-training-managing_your_app_memory/ Random Access Memory(RAM)在任何软件开发环境中都是一个很宝 ...

  10. 关于VO、PO的理解——java的(PO,VO,TO,BO,DAO,POJO)解释

    O/R Mapping 是 Object Relational Mapping(对象关系映射)的缩写.通俗点讲,就是将对象与关系数据库绑定,用对象来表示关系数据. 在O/R Mapping的世界里,有 ...