java代码中的finally块,会在字节码层面上多加一层对于any异常的处理
结论
不论在方法上显式抛出异常了,还是在代码块中try-catch了,如果代码块中存在finally块,当前方法的Code属性中就会出现异常表信息,且Code属性中bytecode部分会多出一套对any异常的处理
这篇文章部分细节不会说明
对比加和不加finally块
首先是不加finally块的
public class Study3 {
public void test() {
try {
InputStream in = new FileInputStream("AAA");
ServerSocket socket = new ServerSocket(9999);
socket.accept();
} catch (Exception e) {
e.printStackTrace();
}
}
}
我们使用javap -verbose 来反编译我们写的类
其他部分我们不关注,只关注 test方法这一块
我们在上图中 关注红框部分,首先是max_locals= 3最大局部变量slot占据数量是3,我们知道非静态方法中,jvm会将对当前类对象引用隐式传入方法中,我们看局部变量表部分,我们catch的异常e和try中变量in共用了同一个1号slot,原因是因为try 和catch的域不同,出现异常被catch捕获了,try里面变量生命周期结束,所以catch中e可以占用之前try里面变量的slot。
如果可以请读一下Code中byteCode部分,加finally之后会发生变化
注意此时异常表 Exception table里面存在是我们定义的对 Exception异常的捕获
然后我们加上finally块(注意finally块里面必须有代码,若没有代码则跟等同于没有finally块)
public void test() {
try {
InputStream in = new FileInputStream("AAA");
ServerSocket socket = new ServerSocket(9999);
socket.accept();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("aaa");
}
}
加finally块之后最显著变化,我们max_locals变成了4,在Code属性中byteCode体现在多了一部分对any异常处理的代码,看图中红框部分 , astore_3 将对除Exception以外的any异常抓出并存储到本地slot是3的变量里面 ,在这里就跟我们正常catch中异常处理不同了,因为catch里面异常变量会存储在我们已有的slot内,而加finally额外多出对any异常处理的异常变量则会额外占用一个slot位置,这个局部变量不会体现在局部变量表 LocalVariableTable里面,所以我们在局部变量表里面看到最大的索引是2
在显式抛出异常的方法中加finally块我就不演示了,显式抛出异常的方法中如果没有finally块,反编译结果中只会有Exceptions属性,不会有Exception table异常表信息,如果加了finally块,就会多出异常表信息,里面是对any异常做的处理,大家可以自己试一下
不喜勿喷,有问题请留言