Java:当InterruptedException被扔进捕获块时,最后似乎两次被执行
在以下代码中:
void foo() throws InterruptedException {
try {
f1();
}
catch (InterruptedException e) {
f2();
throw e;
}
finally {
f3(); //breakpoint hit twice
}
}
InterruptedException
由f1()
抛出,>
block被击中两次,但是最后
中的断点f3 ()
在调试时仅输入一次。我想知道这是否正常。
In the following code:
void foo() throws InterruptedException {
try {
f1();
}
catch (InterruptedException e) {
f2();
throw e;
}
finally {
f3(); //breakpoint hit twice
}
}
When InterruptedException
is thrown by f1()
, the breakpoint in the finally
block is hit twice, but f3()
is entered only once while debugging. I'm wondering if this is normal.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这可能与尝试/最终的方式有关,当时将字节变成字节码(如.. jdk ... 6?它已经很长时间了,但是在遥远的过去,Opcodes JMP和RET用于此;这些opcodes不再由
javac
发射,并且很长时间以来一直没有出现)。最后块只是重复。如果需要的话,很多时候。 Java基本上将其翻译成“抓住任何东西,运行最后的块,然后再重新捕捉到', +'...,并在Try Block的主体末尾复制此代码, +'...和在每个捕获块的末尾复制此代码'。
因此,在您的示例代码中,您的
最后
块实际上存在于您的编译字节 3次中中。您的代码是语法首先从:to:
caveat1:尽管有其他簿记,
f3()
并未重新启动以响应抛出异常本身。在Java代码中很难轻松编写,在字节码中,它的琐碎 - 通过声明“ opcodes范围”来尝试/捕获块?如果发生异常,请跳到此代码。f3()
在尝试块中的重复根本不是范围的一部分。caveat2:生成的字节码足够有效,只能使每一个捕获块最终具有一次。
因此,您的类文件中有许多不同的字节码,它们都具有相同的“行号”。调试从根本上发生在字节码中(例如,当您设置断点时,选择一条行。但是,某些系统需要将该行转换为实际字节码,并分解字节码。在这种情况下,这很棘手:您实际上是一行,您实际上是断点点有3个完全不同的字节码
。显然,如果您想弄清楚为什么会发生,甚至可以撰写PR来解决该问题,那么这是我可以开始
的通过
javap -c
blocked block/
javac test.java < 代码>显示:
分解:您可以轻松地查看
c
的加载方式三次,但是a
和b
仅一次,这很奇怪鉴于源代码中仅提到C一次 - 直到您意识到最后
块在整个地方都被复制。This is possibly related to the way try/finally is contemporarily turned into bytecode (as in, since.. JDK... 6? It's been a long long time, but in the distant past, opcodes JMP and RET were used for this; those opcodes are no longer emitted by
javac
and haven't been for a very very long time).The finally block is just repeated. Loads of times, if needed. java translates it to, basically, 'catch anything, run the finally block, then rethrow whatever you caught', + '... and duplicate this code at the end of the body of the try block', + '... and duplicate this code at the end of each and every catch block'.
Thus, in your example code, your
finally
block is actually present in your compiled bytecode 3 times. Your code is syntax desugared first from:to:
CAVEAT1: Though, with additional bookkeeping that
f3()
isn't re-invoked in response to throwing an exception itself. In java code that's hard to easily write, in bytecode its trivial - try/catch blocks work by declaring 'this range of opcodes? Jump to this code if exceptions occur'. Thef3()
duplication in the try block simply isn't part of the range.CAVEAT2: The bytecode generated is efficient enough to only have the finally body once per catch block.
Hence, you have many different bytecode in your class file that all has the same 'line number'. Debugging fundamentally occurs in bytecode (e.g. when you set a breakpoint, you pick a line. However, some system needs to translate that line to an actual bytecode, and breakpoint that bytecode. In this case, that's tricky: The one line you breakpoint actually has 3 completely different bytecode items. Presumably, your debugger adds breakpoint hooks to all of them.
Just guessing, but it's easy to say how this leads to accidental double firing. It shouldn't - your debugger is clearly itself buggy (heh), but if you want to figure out why its happening, or even help out and write a PR to fix the problem, this is where I'd start.
You can check this 'whaaaa? Are
finally
blocks duplicated this much? Crazy!' stuff by usingjavap -c
, which shows you bytecode.For example:
Then
javac Test.java; javap -c Test
shows:breaking that down: You can easily see how
C
is loaded three times, butA
andB
only once, which is bizarre given that C is only mentioned once in the source code - until you realize thatfinally
blocks are duplicated all over the place.如果您通过说明抛出的例外,则在方法中抛出异常,则您在方法中不会处理它。
实际上,您共享的代码有很多我无法显示我的示例的错误,因此我将显示我的示例。
可以说,您有一种称为foo()的方法,现在会引发异常
,如果要在
foo()
方法中使用foo2()
方法,那么您要么声明foo2()
作为抛出 exceptiondistibbyzero
,或者您应该在foo2()
方法中处理它。 不要像这样的同时做:
或以下:
该最后一个foo2()代码的输出既不
例外。
我受够了。
或
抓住。
我受够了。
0 //因为INT类型初始化为零。
If you throw an exception in a method by stating it throws the exception, then you do not handle it inside the method.
Actually the code you shared has lots of mistakes that I can't show my example, so I'll show my example.
Lets say you have a method called foo() that throws an exception
Now, if you want to use
foo()
method in afoo2()
method, then you either declare thefoo2()
as throws ExceptionDivisionByZero
or you should handle it inside thefoo2()
method. DO NOT DO BOTHLike this:
or this:
output of this last foo2() code is either
No Exception.
I'm done.
or
Caught.
I'm done.
0 //because int type initialized to zero.