Skip to content
Advertisement

Is try-with-resource not safe when declaring multiple effectively final resources?

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.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement