实验代码

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;