Since Java 9 we can use effectively final variables in try-with-resources.
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?
Advertisement
Answer
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.