首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

关于 Java 中 finally 话语块的深度辨析(转)

2012-12-26 
关于 Java 中 finally 语句块的深度辨析(转)可不能小看这个简单的 finally,看似简单的问题背后,却隐藏了无

关于 Java 中 finally 语句块的深度辨析(转)
可不能小看这个简单的 finally,看似简单的问题背后,却隐藏了无数的玄机。接下来我就带您一步一步的揭开这个 finally 的神秘面纱。

问题分析

首先来问大家一个问题:finally 语句块一定会执行吗?

很多人都认为 finally 语句块是肯定要执行的,其中也包括一些很有经验的 Java 程序员。可惜并不像大多人所认为的那样,对于这个问题,答案当然是否定的,我们先来看下面这个例子。


清单 1.



清单 1 的执行结果如下:

 


另外,如果去掉上例中被注释的两条语句前的注释符,执行结果则是:



清单 2 的执行结果如下:


清单 4 的执行结果为:

清单 5 的执行结果:



清单 6 的执行结果:



图 1. getValue()函数正常执行的情况


由上图,我们可以清晰的看出,在 finally 语句块(iinc 0, 1)执行之前,getValue()方法保存了其返回值(1)到本地表量表中 1 的位置,完成这个任务的指令是 istore_1;然后执行 finally 语句块(iinc 0, 1),finally 语句块把位于 0 这个位置的本地变量表中的值加 1,变成 2;待 finally 语句块执行完毕之后,把本地表量表中 1 的位置上值恢复到操作数栈(iload_1),最后执行 ireturn 指令把当前操作数栈中的值(1)返回给其调用者(main)。这就是为什么清单 6 的执行结果是 1,而不是 2 的原因。

再让我们来看看异常执行的情况。是不是有人会问,你的清单 6 中都没有 catch 语句,哪来的异常处理呢?我觉得这是一个好问题,其实,即使没有 catch 语句,Java 编译器编译出的字节码中还是有默认的异常处理的,别忘了,除了需要捕获的异常,还可能有不需捕获的异常(如:RunTimeException 和 Error)。

从 getValue()方法的字节码中,我们可以看到它的异常处理表(exception table), 如下:

Exception table:

from to target type

2 4 9 any

它的意思是说:如果从 2 到 4 这段指令出现异常,则由从 9 开始的指令来处理。


图 2. getValue()函数异常执行的情况


先说明一点,上图中的 exception 其实应该是 exception 对象的引用,为了方便说明,我直接把它写成 exception 了。

由上图(图 2)可知,当从 2 到 4 这段指令出现异常时,将会产生一个 exception 对象,并且把它压入当前操作数栈的栈顶。接下来是 astore_2 这条指令,它负责把 exception 对象保存到本地变量表中 2 的位置,然后执行 finally 语句块,待 finally 语句块执行完毕后,再由 aload_2 这条指令把预先存储的 exception 对象恢复到操作数栈中,最后由 athrow 指令将其返回给该方法的调用者(main)。

通过以上的分析,大家应该已经清楚 try-catch-finally 语句块的执行流程了吧!

为了更具说服力,我们还是来引经据典吧!大家可以不相信我,难道还不相信“高司令”(Gosling)吗?下面这段仍然摘自 Java 语言规范第四版 《 The Java? Programming Language, Fourth Edition 》,请读者自己体会吧!


清单 7 的执行结果:



清单 8 的执行结果:

 String tmp = test1();  return tmp; 




这样,就应该清楚为什么是上面所示的执行结果了吧!

好了,就写到这吧!希望大家看完这篇文章能够有所收获!


热点排行