此文已由作者徐赟授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
一、 问几个问题
在说明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信息,每个条目包含四个属性:
通过这四个参数,是不是就能描述一段try...catch代码段了呢
2. java代码的throw exception; 语句会被编译成athrow执行(当然还包括之前的堆栈操作指令),athrow执行的执行逻辑是“
这就是try...catch的执行机制了。
3. 为什么finally这么坚强,不管try...catch搞出什么幺蛾子都会被执行,看看上面的字节码就知道了。
4. A或B代码中如果有return,C代码会插入到return之前,以保证C代码一定会被执行。
5. Exception table表中类型为any的条目只包裹了A,B代码块,C代码块并未被包裹,否则如果在C代码块抛出异常,逻辑就会陷死在C代码中(抛出的异常又被any捕获回来)
try...catch的执行机制就是这样,希望这篇文章无愧于标题所说的详解。
网易云免费体验馆,0成本体验20+款云产品!
更多网易技术、产品、运营经验分享请点击。