天天看点

java try catch详解_java try...catch...finally机制详解

此文已由作者徐赟授权网易云社区发布。

欢迎访问

一、 问几个问题

在说明try...catch...finally机制前,先问几个问题作为文章的引子。

有这样一种结构

try {

A; // A代表被try包裹的代码块

} catch (FileNotFoundException e) {

B;// B代表被catch包裹的代码块

} finally {

C;// C代表被finally包裹的代码块

}

1. 什么是try...catch...finally?

当A代码块执行抛出FileNotFoundException异常时,B代码块被执行。无论A中是否有异常,C代码块都会被执行。

2. 如果A代码块中有return呢,C还会不会被执行?

会被执行,另外B中如果有return,在A抛出FileNotFoundException异常的时,C依然会在B之后执行。

3. 如果A或B中抛出异常,C会执行么?

会执行,而且finally执行后,异常会接着抛出去。

4. 什么情况下,C代码不会被执行?

当代码进入try...catch区域后,基本上可以说finally代码块一定会被执行,只有两种极端的情况finally不会执行

1) JVM crash了(不好不坏,偏偏在这个时间点crash)

2) 当用户调用System.exit(0)主动停止JVM

除此之外的任何情况,C代码都无可避免的被执行。

二、 分析

为什么try...catch...finally会表现出这样的特质,逻辑都蕴藏在java字节码里。

try {

A;

} catch (FileNotFoundException e) {

B1;

} catch (ClassNotFoundException e) {

B2;

} finally {

C;

}

这样结构的java代码编译成字节码后会变为如下形式

Code:

stack=2, locals=3, args_size=1

0: A // 为了使结构清晰,这里用A代表A代码块的字节码逻辑

12: goto 66

15: B1 // catch了两个异常分别用B1,B2表示

24: C

32: goto 74

35: B2

44: C

52: goto 74

55: astore_2

56: C

64: aload_2

65: athrow

66: C

74: return

Exception table:

from to target type

0 12 15 Class java/io/FileNotFoundException

0 12 35 Class java/lang/ClassNotFoundException

0 24 55 any

35 44 55 any

1. 带有try...catch...finally的方法会在java字节码中自动生成一个属于该方法的Exception table,记录了方法的try...catch信息,每个条目包含四个属性:

from:try代码块从哪一行字节码开始

to:try代码块到哪一行字节码结束

target:try代码块中出现异常后,程序应该跳转到哪一行字节码继续执行(Exception对应的catch代码开头)

type:捕获何种类型的异常

通过这四个参数,是不是就能描述一段try...catch代码段了呢

2. java代码的throw exception; 语句会被编译成athrow执行(当然还包括之前的堆栈操作指令),athrow执行的执行逻辑是“

首先到当前所在方法的Exception table中寻找是否有满足条件的try...catch代码块(堆栈中存放了抛出的异常对象和抛出异常的位置)

如果存在符合条件的catch代码块,异常被消化掉

如果不存在,则通过弹出栈帧的方式跳转到调用该方法的方法中(方法调用逻辑中,会将方法跳转现场信息压入线程栈),检测这一层方法的Exception table表中是否有满足条件的条目。

如果异常一直没有被吃掉,就会逐级遍历相关方法,直到最顶层的main方法或run方法中,错误消息堆栈被打印到控制台,该线程被终止,这就算这个exception起义成功了。

这就是try...catch的执行机制了。

3. 为什么finally这么坚强,不管try...catch搞出什么幺蛾子都会被执行,看看上面的字节码就知道了。

A代码执行过程如果不抛出异常,goto 66 会使代码跳转到C代码区(finally)执行,执行完就return了

A代码抛出FileNotFoundException异常,这是会在Exception table中锁定一下这条信息

0    12    15   Class java/io/FileNotFoundException        这里target是15,会向goto一样将代码引导到B1处执行,随后接着执行C,再就return了

A代码抛出NullPointException,这个我们没有事先catch,但在搜索Exception table表时会找到如下信息

0    24    55   any        这里的any类型保证了任何幺蛾子发生在0-24都会被捕获,代码会被引导到55处,这里通过注释的方式阐述:

55: astore_2       // 从堆栈中拿出原始异常NullPointException对象,存放在临时变量2中

56: C            // 执行C代码块(finally逻辑)

64: aload_2        // 把临时变量2中的异常对象压入内存

65: athrow        // 把原始异常继续抛出

总结起来就是,finally会响应try语句中抛出的异常,并且会将异常继续抛出去

另外   (35    44    55   any)   这一句也保证了catch中抛出的异常也会被finally响应,并继续抛出

4. A或B代码中如果有return,C代码会插入到return之前,以保证C代码一定会被执行。

5. Exception table表中类型为any的条目只包裹了A,B代码块,C代码块并未被包裹,否则如果在C代码块抛出异常,逻辑就会陷死在C代码中(抛出的异常又被any捕获回来)

try...catch的执行机制就是这样,希望这篇文章无愧于标题所说的详解。

网易云

更多网易技术、产品、运营经验分享请