读:《java中的finally语句块的深度辨析》

《java中的finally语句块的深度辨析》满有意思的文章。作下笔记。

作者第一句提出一个问题:finally 语句块一定会执行吗?(这里是辩术吧...)
他的说法是不一定,被interrupted或者killed的情况不会被执行,并提出一个例子。
(我觉得不太算强词夺理,以后多线程的时候可以长个心眼)

    public static int test() {
int i = 1;
try {
System.out.println(
"try block");
System.exit(
0);
return i;
}
finally {
System.out.println(
"finally block");
}
}



当然上面这点,称不上有意思。人家继续举了一个举例

 public class Test { 
public static void main(String[] args) {
System.out.println(
"return value of getValue(): " + getValue());
}

public static int getValue() {
int i = 1;
try {
return i;
}
finally {
i
++;
}
}
}

这个例子的结果是:1。为什么不是2呢?  finally语句没有执行么?(这就是上面我说的辩术的误导效果吧... )


真实情况要看下对应的字节码

 public static int getValue(); 
Code:
0: iconst_1 //Push int constant
1: istore_0 // Store int into local variable
2: iload_0 // Load int from local variable
3: istore_1 // 结果存在本地变量表1
4: iinc 0, 1 // Increment local variable by constant
7: iload_1 // 从本地变量表1取回结果
8: ireturn //Return int from method
9: astore_2
10: iinc 0, 1
13: aload_2
14: athrow
Exception table:
from to target type
2 4 9 any
9 10 9 any
}

这里牵涉到两部分类容:

1、The JavaTM Virtual Machine Specification, Second Edition 》中 7.13 节 Compiling finally。那里详细介绍了 Java 虚拟机是如何编译 finally 语句块。实际上,Java 虚拟机会把 finally 语句块作为 subroutine直接插入到 try 语句块或者 catch 语句块的控制转移语句之前。

2、但是,还有另外一个不可忽视的因素,那就是在执行 subroutine(也就是 finally 语句块)之前,try 或者 catch 语句块会保留其返回值到本地变量表(Local Variable Table)中待 subroutine 执行完毕之后,再恢复保留的返回值到操作数栈中,然后通过 return 或者 throw 语句将其返回给该方法的调用者(invoker)。请注意,前文中我们曾经提到过 return、throw 和 break、continue 的区别,对于这条规则(保留返回值),只适用于 return 和 throw 语句,不适用于 break 和 continue 语句,因为它们根本就没有返回值。



posted @ 2011-08-10 17:22  倚楼无语F5  阅读(216)  评论(0编辑  收藏  举报