Java中的 finally 与 return
Contents
实验代码
package org.agoncal.sample.jmh;
/**
* Created by emacsist on 2017/7/14.
*/
public class TestFinallyClass {
public static void main(String[] args) {
System.out.println(testFinally(10));
}
public static int testFinally(int i) {
try {
return i + 1;
} finally {
i+=10;
return i + 2;
}
}
}
字节码
Code:
stack=2, locals=3, args_size=1
0: iload_0 将 LocalVariableTable 中 slot 为 0 的变量压入栈
1: iconst_1 将常量 int 类型的 1 压入栈
2: iadd 将栈顶的两个 int 弹出,并相加,最后将结果压入栈 (即 i+1)
3: istore_1 将栈顶的 int 弹出,并保存到局部变量表中 slot 为 1 的局部变量(这个是编译器处理生成的)
4: iinc 0, 10 将局部变量 slot 为0的变量,增加10,即 (i+=10)
7: iload_0 将 slot 为0的变量(即 i)压入栈
8: iconst_2 将常量 int 类型的 2 压入栈
9: iadd 将栈顶的两个 int 弹出并相加,最后将结果压入栈
10: ireturn 将栈顶的结果,放到返回值的存储位置中
11: astore_2 从栈顶弹出一个对象引用,并保存到 slot 为2(这个是编译器处理生成的) 中
12: iinc 0, 10 将局部变量 slot 为0的变量,增加10,即 (i+=10)
15: iload_0 将 slot 为0的变量(即 i)压入栈
16: iconst_2 将常量 int 类型的 2 压入栈
17: iadd 将栈顶的两个 int 弹出并相加,最后将结果压入栈
18: ireturn 将栈顶的结果,放到返回值的存储位置中
Exception table:
from to target type
0 4 11 any 从指令位置0到4之间(不包括4,即 0<=pc<4),执行完后,无条件跳转到指令11位置处。
LocalVariableTable:
Start Length Slot Name Signature
0 19 0 i I
伪代码:
int tmpVar = i + 1;(tmpVar 就是编译器生成的 slot 为1 的变量,slot 0是变量 i)
执行完这一行,后,它就要跳转到指令11处开始执行了。即:
i+=10;
return i+2;
但是,可以看到由于编译器执行了优化,它直接复制了 finally 的语句,拼接在指令 4-10 处了。可以看到 4-10 的指令,与 11-18 处的指令是完全一样的。
所以,对于编译后真正执行的代码如下:
int tmpVar = i+1;
i+=10;
return i+2;
finally 没 return 的情况
stack=2, locals=3, args_size=1
0: iload_0
1: iconst_1
2: iadd
3: istore_1
4: iinc 0, 10
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_0
11: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
14: iload_1
15: ireturn
16: astore_2
17: iinc 0, 10
20: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
23: iload_0
24: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
27: aload_2
28: athrow
Exception table:
from to target type
0 4 16 any
伪代码:(通过字节码可以看到,它也是优化后的字节码的,它将 finally 语句的部分,复制在上面了)
int tmpVar = i + 1;
i+=10;
System.out.println(i);
return tmpVar;