先上一段很简单,且不考虑健壮性的源码:
import java.io.FileInputStream;
import java.io.IOException;
public class TryCatchFinallyTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
FileInputStream fips = null;
try {
fips = new FileInputStream("hello.txt");
fips.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
fips.close();
}
}
}
然后上一段这段代码在eclipse编译级别为1.4、没有inline finally块时编译出的字节码:
// Compiled from TryCatchFinallyTest.java (version 1.2 : 46.0, super bit)
public class TryCatchFinallyTest {
// Method descriptor #6 ()V
// Stack: 1, Locals: 1
public TryCatchFinallyTest();
0 aload_0 [this]
1 invokespecial java.lang.Object() [8]
4 return
Line numbers:
[pc: 0, line: 6]
Local variable table:
[pc: 0, pc: 5] local: this index: 0 type: TryCatchFinallyTest
// Method descriptor #15 ([Ljava/lang/String;)V
// Stack: 3, Locals: 5
public static void main(java.lang.String[] args) throws java.io.IOException;
0 aconst_null
1 astore_1 [fips]
2 new java.io.FileInputStream [19]
5 dup
6 ldc <String "hello.txt"> [21]
8 invokespecial java.io.FileInputStream(java.lang.String) [23]
11 astore_1 [fips]
12 aload_1 [fips]
13 invokevirtual java.io.FileInputStream.read() : int [26]
16 pop
17 goto 43
20 astore_2 [e]
21 aload_2 [e]
22 invokevirtual java.io.IOException.printStackTrace() : void [30]
25 goto 43
28 astore 4
30 jsr 36
33 aload 4
35 athrow
36 astore_3
37 aload_1 [fips]
38 invokevirtual java.io.FileInputStream.close() : void [33]
41 ret 3
43 jsr 36
46 return
Exception Table:
[pc: 2, pc: 17] -> 20 when : java.io.IOException
[pc: 2, pc: 25] -> 28 when : any
[pc: 43, pc: 46] -> 28 when : any
Line numbers:
......
Local variable table:
[pc: 0, pc: 47] local: args index: 0 type: java.lang.String[]
[pc: 2, pc: 47] local: fips index: 1 type: java.io.FileInputStream
[pc: 21, pc: 25] local: e index: 2 type: java.io.IOException
}
2-17是try块代码;
20-25是catch块代码;
28-35是编译期生产的catch块之外的异常即any类型异常要执行的代码;
36-41是finally块代码;
43-46是编译期生成的字节码;
其中偏移量17和25处都是goto 43,然后jsr到finally,即try和catch块都是到43;any类型中有一条指令jsr到finally块。
归纳总结下,try/catch/finally结构中:
1、try/catch块翻译成指令后最后一条字节码指令都是goto到一个编译出来的块A(43-46),A第一条指令(43)即jsr到finally块第一条指令,finally完就ret到A第二条指令即return(46)
2、any块,即catch之外的异常类型,也即any,是jvm自己构造了一个指令块B(28-35),先store下这种异常实例到局部变量表(28),然后jsr到finally块中(30),finally完就ret到B的第三条指令(33)执行,load出之前存储到局部变量表的异常实例,然后athrow(35)。
JSR指令后边一般是:
1、load返回值然后return的指令(try/catch块,有返回值)
2、直接return(try/catch块,无返回值)
3、load出异常然后athrow(catch any)