Return 尝试使用资源。这是 JVM 的正确行为吗?
Return in try with resources. Is it correct behaviour of JVM?
在下面的代码示例中,我希望将 1 作为方法 testM()
的 return 值。但是由于 TestAutoCloseable.close()
方法中的异常,我得到了意外的行为。
我的问题是:"Is it a normal behaviour of 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 resources 语句中使用 return 或 break 语句。应该是反模式。
try-with-resources
语句如何工作的详细信息在 JLS 的 this section 中。在您的情况下,它是一个 extended try-with-resources
因为它有一个 catch
子句,如以下引用中所定义(请注意末尾突出显示的语句)。
A try-with-resources statement with at least one catch clause and/or a finally clause is called an extended try-with-resources statement.
The meaning of an extended try-with-resources statement:
try ResourceSpecification
Block
[Catches]
[Finally]
is given by the following translation to a basic try-with-resources statement nested inside a try-catch or try-finally or try-catch-finally statement:
try {
try ResourceSpecification <--- exception thrown in this basic try-with-resources
Block
}
[Catches]
[Finally]
The effect of the translation is to put the resource specification "inside" the try statement. This allows a catch clause of an extended try-with-resources statement to catch an exception due to the automatic initialization or closing of any resource.
这意味着关闭资源发生在内部外部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;
}
简而言之,当您的 try-with-resource 块退出时,会抛出一个 IOException(因为您是从 close() 抛出它的,所以值 1 从未从该方法返回,而是 JVM 移动到 catch 块,因为根据规则,一旦发生任何异常,try 块中的所有剩余代码都不会被执行,而是 JVM 移动到catch block.so 现在你的 catch 块运行,然后你剩下的代码被执行
在下面的代码示例中,我希望将 1 作为方法 testM()
的 return 值。但是由于 TestAutoCloseable.close()
方法中的异常,我得到了意外的行为。
我的问题是:"Is it a normal behaviour of 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 resources 语句中使用 return 或 break 语句。应该是反模式。
try-with-resources
语句如何工作的详细信息在 JLS 的 this section 中。在您的情况下,它是一个 extended try-with-resources
因为它有一个 catch
子句,如以下引用中所定义(请注意末尾突出显示的语句)。
A try-with-resources statement with at least one catch clause and/or a finally clause is called an extended try-with-resources statement.
The meaning of an extended try-with-resources statement:
try ResourceSpecification Block [Catches] [Finally]
is given by the following translation to a basic try-with-resources statement nested inside a try-catch or try-finally or try-catch-finally statement:
try {
try ResourceSpecification <--- exception thrown in this basic try-with-resources
Block
}
[Catches]
[Finally]
The effect of the translation is to put the resource specification "inside" the try statement. This allows a catch clause of an extended try-with-resources statement to catch an exception due to the automatic initialization or closing of any resource.
这意味着关闭资源发生在内部外部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;
}
简而言之,当您的 try-with-resource 块退出时,会抛出一个 IOException(因为您是从 close() 抛出它的,所以值 1 从未从该方法返回,而是 JVM 移动到 catch 块,因为根据规则,一旦发生任何异常,try 块中的所有剩余代码都不会被执行,而是 JVM 移动到catch block.so 现在你的 catch 块运行,然后你剩下的代码被执行