根据Java语言规范,Section §14.20.2
首先执行try块,执行带有finally块的try语句。然后有一个选择:
- 如果try块的执行正常完成,那么finally 块被执行,然后有一个选择:
- 如果finally块正常完成,则try语句正常完成。
- 如果finally块因为S而突然完成,则try语句突然完成,原因是S
如果我正确解释它,那么在执行try block finally之后会被调用,但是这一切是如何工作的以及为什么我得到了输出,
public static int TestTryFinallyBlock()
{
int i =0;
try
{
i= 10; //Perform some more operation
return i;
}
finally
{
i = 40;
}
}
public static void main( String[] args )
{
int i1 = TestTryFinallyBlock(); //Here the output was 10 not 40
}
我想知道这件事是如何产生输出10的。
当执行try块并且遇到return语句时,输出值已经被推送到堆栈,然后执行finally块
我知道首先遇到返回然后最后阻塞运行所以输出是10,但是
如何解释jvm或jvm如何处理或转换try finally块?
是jvm使用GOTO部分跳转部分到最后部分还是堆栈已经被维护了?
答案 0 :(得分:3)
经过一番搜索并看到生成了什么字节码后,我发现实际上看起来没有最终的块,也没有JVM生成的跳转或goto语句。
上面的代码翻译为(如果我正确解释字节代码,如果我错了请纠正我)
public static int TestTryFinallyBlock()
{
int returnValue; //A temporary return variable
try
{
int i = 0;
i = 10;
returnValue = i;
i = 40;
return returnValue;
}
catch (RuntimeException e)
{
i = 40; //finally section code id copied here too
throw e;
}
}
指向注意:如果'i'
是对可变类对象的引用,并且在finally块中更改了对象的内容,那么这些更改将会被反映出来在返回的值中。
答案 1 :(得分:2)
try-finally语句的编译类似于try-catch的编译。在try语句之外传递控制之前,无论该传输是正常还是突然,因为抛出了异常,必须首先执行finally子句。对于这个简单的例子:
void tryFinally() {
try {
tryItOut();
} finally {
wrapItUp();
}
}
编译后的代码是:
Method void tryFinally()
0 aload_0 // Beginning of try block
1 invokevirtual #6 // Method Example.tryItOut()V
4 jsr 14 // Call finally block
7 return // End of try block
8 astore_1 // Beginning of handler for any throw
9 jsr 14 // Call finally block
12 aload_1 // Push thrown value
13 athrow // ...and rethrow value to the invoker
14 astore_2 // Beginning of finally block
15 aload_0 // Push this
16 invokevirtual #5 // Method Example.wrapItUp()V
19 ret 2 // Return from finally block
Exception table:
From To Target Type
0 4 8 any
有四种方法可以在try语句之外传递控制:通过返回该块的底部,返回,执行break或continue语句,或者引发异常。
要了解更多有关javac如何解释finally块的信息。请参阅JLS - 3.13. Compiling finally
答案 2 :(得分:1)
当您输入返回值时,该方法已准备好返回10. 10在堆栈上作为返回值。执行finally块并将i
设置为40 - 但i
与返回值的位置不同。现在,如果有副作用,如:
public static int TestTryFinallyBlock()
{
int i =0;
try
{
i= 10; //Perform some more operation
return i;
}
finally
{
i = 40;
System.out.println("local: "+i);
}
}
40 将打印出来。
答案 3 :(得分:1)
这是因为return语句的功能以及它与try语句的交互方式。
JLS的Section §14.17描述了return语句。
带有Expression的return语句尝试将控制权转移给包含它的方法的调用者; Expression的值成为方法调用的值。更确切地说,执行这样的return语句首先评估Expression。如果表达式的评估由于某种原因突然完成,则返回语句因此而突然完成。如果表达式的评估正常完成,产生值V,则return语句突然完成,原因是返回值为V.
最后一句表示如果return语句的表达式正常评估,则return语句 abrutptly 完成。在您的示例中,由于try
语句而导致return
块突然终止,原因是return
值为10 {i
已评估价值10)。
由于在您的示例中,return
正在尝试使用finally块,因此JLS的Section §14.20.2告诉我们接下来会发生什么:
- 如果由于任何其他原因导致try块的执行突然完成 R,然后执行finally块,然后有一个选择:
- 如果finally块正常完成,则try语句突然完成,原因是R。
- 如果finally块因为原因S而突然完成,则try语句因原因S(以及原因R被丢弃)而完全崩溃。
因此,由于返回语句被计算到值10,因为try
块突然终止,并且因为finally块正常完成,所以该方法返回10.
答案 4 :(得分:0)
现在 i 的值是40,但你没有得到 40 ,因为在获得 40之前你得到了(returned
)这个值强>
就像
i=10
return i
i=40
if return here,you get 40
虽然不是一个好习惯,但仅限于演示。
public static int TestTryFinallyBlock()
{
int i =0;
try
{
i= 10; //Perform some more operation
}
finally
{
i = 40;
return i;
}
}
现在 40 的值将进入 i 。
* 作为旁注: *从不编写除资源清理之外的任何业务逻辑。这会导致可读性并导致错误。