在下面的代码示例中,我希望将1作为方法testM()
的返回值。但是由于TestAutoCloseable.close()
方法中的异常,我得到了意想不到的行为。
我的问题是:“这是JVM的正常行为吗?”
public static void main(String[] args) {
ProgrammerTwo programmerTwo = new ProgrammerTwo();
System.out.println(programmerTwo.testM());
}
int testM() {
try (TestAutoCloseable closable = new TestAutoCloseable()) {
System.out.println("Do first return");
return 1;
} catch (IOException e) {
System.out.println("handled");
}
System.out.println("Do something, that shouldn't do if first return have happened");
return 2;
}
static class TestAutoCloseable implements AutoCloseable {
@Override
public void close() throws IOException {
throw new IOException();
}
}
因为如果它是正常行为,我们不应该在try with resource语句中使用return或break语句。它应该是反模式的。
答案 0 :(得分:1)
try-with-resources
语句如何工作的详细信息位于JLS的this section中。在您的情况下,它是扩展 try-with-resources
,因为它具有下面引用中定义的catch
子句(请注意最后突出显示的语句)。
带有至少一个catch子句和/或finally子句的try-with-resources语句称为扩展的try-with-resources语句。
扩展的try-with-resources语句的含义:
try ResourceSpecification Block [Catches] [Finally]
通过以下转换给出嵌套在try-catch或try-finally或try-catch-finally语句中的基本try-with-resources语句:
try {
try ResourceSpecification <--- exception thrown in this basic try-with-resources
Block
}
[Catches]
[Finally]
翻译的效果是将资源规范放在try语句的“内部”。 这允许扩展的try-with-resources语句的catch子句捕获由于自动初始化或关闭任何资源而导致的异常。
这意味着关闭资源会在外部try
块的主体内发生,导致在catch
块中抛出并处理异常,并控制恢复扩展try-with-resources
语句之后的语句。
实际上,整个方法testM
等同于:
int testM() {
try {
final TestAutoCloseable closable = new TestAutoCloseable();
Throwable #primaryExc = null;
try {
System.out.println("Do first return");
return 1;
} catch (Throwable #t) {
#primaryExc = #t;
throw #t;
} finally {
if (closable != null) {
if (#primaryExc != null) {
try {
closable.close();
} catch (Throwable #suppressedExc) {
#primaryExc.addSuppressed(#suppressedExc);
}
} else {
closable.close();
}
}
}
} catch (IOException e) {
System.out.println("handled");
}
System.out.println("Do something, that shouldn't do if first return have happened");
return 2;
}
答案 1 :(得分:0)
简单来说,当你的try-with-resource块退出时,抛出一个IOException(因为你从 close()抛出它,所以值 1 从来没有从方法返回,而是JVM移动到catch块,因为根据规则,一旦发生任何异常,try块中的所有重新映射代码都不会被执行而JVM移动到catch块。所以现在你的catch块运行,然后执行剩余的代码