问题
Break doesn't work in try with resources, but work in try without resources!
This is a simple example for this situation. I caught this "bug" in work project.
When I use try without resources
try {
Resources resources = getResources()
// some code here, look below
}
I have only one iteration of my cycle, and it's right because I have the condition "if true then break", but when I changed try without recourse on try WITH resources.
try (Resources resources = getResources()) {
// some code here, look below
}
I was shocked! The cycle became endless! Why?
Full code:
public class Test {
public static void testTryWithResAndBreak() {
while (true) {
System.out.println("we are in (while(true))");
try (Resources resources = getResources()) {
System.out.println("We are in try block");
if (true) {
System.out.println("We are in the if(true) now! Next step is break");
break;
}
System.out.println("OOOOO___OOOO WE ARE HERE!!!");
resources.writeSomething();
} catch (Exception e) {
System.out.println("Catched exception");
}
}
}
private static class Resources implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("Resources closed");
throw new Exception("Exception after closed resources!");
}
public void writeSomething() {
System.out.println("i wrote something");
}
}
private static Resources getResources() {
return new Resources();
}
public static void main(String[] args) {
testTryWithResAndBreak();
}
}
回答1:
The cycle is endless because your close is occurring at the end of the try scope. This throws an exception, which interrupts the break operation. The exception handler (which is INSIDE the while loop) then catches it, and continues to the end of the loop, and since the loop condition is 'true', continues forever. When you don't use try-with-resource, the close is never called, so the exception isn't thrown, and the break is not interrupted.
回答2:
Just before the break
is executed, the close
method on the Resource
is called. This can be seen in the byte code:
L9 // Print statement
LINENUMBER 14 L9
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "We are in the if(true) now! Next step is break"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1 // Close method call
LINENUMBER 17 L1
ALOAD 2
IFNULL L10
ALOAD 2
INVOKEVIRTUAL Main$Resources.close ()V
L3 // Then the break
LINENUMBER 15 L3
GOTO L10
But this close
method throws an exception itself, which transfers control over to the catch
block. After the catch
block is done, the while
loop continues its next iteration. So the break
statement will never be executed.
The structure generated by the try-with-resources looks something like this:
try {
Resources resources = null;
try {
resources = getResources();
if (true) {
break;
}
} catch (Exception e) {
} finally {
if(resources != null)
resources.close();
}
} catch (Exception e) {
}
This is different from your version, where the inner finally
block already handles the exception, after which the break
is executed. But in the above, the exception is handled by the outer catch
block, after which control is returned to the while
loop.
来源:https://stackoverflow.com/questions/39777022/break-doesnt-work-in-try-with-resources-but-work-in-try-without-resources