void test(int x) {
try {
x += 777;
} finally {
x -= 333;
}
}
反汇编后的代码如下:
test(I)V
TRYCATCHBLOCK L0 L1 L2 null
TRYCATCHBLOCK L2 L3 L2 null
L0 // Start of try block
IINC 1 777 // The body of try block
L1 // Start of finally block in case of successful execution
IINC 1 -333 // Body of finally block
GOTO L4 // End of 'success' finally block
L2 // Start of finally block in case of exception
ASTORE 2 // Remember exception
L3
IINC 1 -333 // Duplicated body of finally block
ALOAD 2 // Load remembered exception
ATHROW // Rethrow the exception
L4 // End of try/finally
RETURN
L5
显然,此声明指定了“ try”部分和“ finally”块的开头:
TRYCATCHBLOCK L0 L1 L2 null
但是下一个声明看起来很奇怪:
TRYCATCHBLOCK L2 L3 L2 null
为什么Java编译器在记住异常时会保护该异常,为什么它会递归地将自身指定为处理程序(即两个
L2
)?#1 楼
一个猜测。我们可以看到没有实际的代码重复,多个trycatch块在失败或失败的不同情况下都充当goto标签(因为还存在finally子句)。如果遵循程序流程,您会发现没有重复发生。#2 楼
我只是使用Java 8编译器对此进行了反汇编,并且不再生成第二个trycatchblocktest(I)V
TRYCATCHBLOCK L0 L1 L2 null
L0
IINC 1 777
L1
IINC 1 -333
L3
GOTO L4
L2
FRAME SAME1 java/lang/Throwable
ASTORE 2
IINC 1 -333
ALOAD 2
ATHROW
L4
FRAME SAME
RETURN
L5
我的猜测是这是JVM忽略的一些遗留处理方法
评论
如果使用catch而不是finally会发生同样的事情吗?@Devolus编号。它添加了单个TRYCATCHBLOCK L0 L1 L2 java / lang / Exception
几年前在SO上也有同样的问题:stackoverflow.com/questions/6386917/…
我同意Devolus。我从未真正在生产代码中看到try {} finally {}。
丹尼尔,不是同一个问题。 “从几年前开始”的问题明确指出,即使有挡木块,他的案子也会发生。