Since Java 9 we can use effectively final variables in try-with-resources. (See JEP 213.)
The example below presents a situation where one of the resources initialization throws an exception.
public static void main(String[] args) {
Resource1 r1 = new Resource1();
Resource2 r2 = new Resource2(); // exception will be thrown
try (r1; r2) {
System.out.println("TryWithResources.main() try");
} catch (Exception e) {
System.out.println("TryWithResources.main() catch");
}
}
static class Resource1 implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("TryWithResources.Resource1.close()");
}
}
static class Resource2 implements AutoCloseable {
public Resource2() {
throw new RuntimeException();
}
@Override
public void close() throws Exception {
System.out.println("TryWithResources.Resource2.close()");
}
}
When I run this example, the only output I get is a RuntimeException, meaning that Resource1 was not closed. That was expected, since it wasn't initialized in the try-with-resources.
But, is this the expected outcome, or am I missing anything?
Because, if this is actually the way it is supposed to work, then It seems to me that this new syntax actually removes a lot of the safety that was brought originally by the try-with-resources statement.
Can someone please confirm if that really is the case? And, if positive, why would we ever use this syntax with multiple resources and take that risk?
I think you're assuming that the "initialization" occurs in the try
statement. The exception is thrown by the constructor before the try-with-resources
is reached. In other words, the line try (r1; r2) {
in itself does not initialize the resources, it just refers to them as variables. It's different than initializing the resource in try
blocks:
try (r1; Resource2 r2 = new Resource2()) { // this causes r1 to close if r2 throws an exception
Having said this, you're right with the point that the new syntax (accessing a final variable) gives flexibility at the expense of a possibility for failing to close previously created resources (as demonstrated in your case). Personally I never had a reason to use that new syntax. There is no good reason I can think of for not creating the resource within the try
statement, after all there is no point of using a resource after it is closed.