Enrique
Enrique

Reputation: 882

What exactly gets caught in an extended try-with-resources statement?

In the following block of code:

try ( /* resources declaration */ ) {
    // some dangerous code
} catch (Exception e) {
    // error handling and reporting
}

What would happen if both the code inside the try block and the automatic close() statement threw exceptions? Which one would get caught in the catch block? Both of them? Only one of them? If so, which one?

Furthermore, what if the try is successful but the close is not? Would the catch block be entered?

Upvotes: 8

Views: 970

Answers (2)

Tunaki
Tunaki

Reputation: 137084

Quoting from the JLS section 14.20.3.1:

In a basic try-with-resources statement that manages a single resource:

  • If the initialization of the resource completes abruptly because of a throw of a value V, then the try-with-resources statement completes abruptly because of a throw of the value V.
  • If the initialization of the resource completes normally, and the try block completes abruptly because of a throw of a value V, then:

    • If the automatic closing of the resource completes normally, then the try-with-resources statement completes abruptly because of a throw of the value V.

    • If the automatic closing of the resource completes abruptly because of a throw of a value V2, then the try-with-resources statement completes abruptly because of a throw of value V with V2 added to the suppressed exception list of V.

  • If the initialization of the resource completes normally, and the try block completes normally, and the automatic closing of the resource completes abruptly because of a throw of a value V, then the try-with-resources statement completes abruptly because of a throw of the value V.

This means that if both the code inside the try block and the automatic close() statement throw an exception, the catch part will handle the exception thrown by the try block, with the exception thrown by close() in the suppressed exceptions.

Also, this means that if the try block is successful but the automatic close() fails, the catch will sill be executed and the catched exception will be the exception thrown by close().


Here's a test to verify this behaviour:

public class Main {
    public static void main(String[] args) throws Exception {
        // try block fails and close() fails
        try (T t = new T()) {
            throw new Exception("thrown by try part");
        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.out.println(e.getSuppressed()[0].getMessage());
        }

        // try block is successful but close() fails
        try (T t = new T()) {
            //
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

class T implements AutoCloseable {
    @Override
    public void close() throws Exception {
        throw new Exception("thrown by close");
    }
}

This code will print

thrown by try part
thrown by close
thrown by close

meaning that the catched exception was the exception thrown by the try part of the code for the first part. For the second part, the catched exception was indeed the exception thrown by close().

Upvotes: 8

Chris
Chris

Reputation: 1742

The exception thrown inside the try block is thrown to the outside world.

While with the try-catch-finally the exception thrown from the finally block would be propagated up the call stack.

InputStream input = null;

    try {
        input = new FileInputStream("file.txt");

        int data = input.read();
        while(data != -1){
            System.out.print((char) data);
            data = input.read();
        }
    } finally {
        if(input != null){
            input.close();
        }
    }

In this case, if an exception occurs in both the try block and the finally block(when the InputStream is closed), the the last one is thrown, even if the exception thrown from the try block would probably be more relevant to propagate.

try(FileInputStream input = new FileInputStream("file.txt")) {

        int data = input.read();
        while(data != -1){
            System.out.print((char) data);
            data = input.read();
        }
    }

While in this case if an exception occurs in both the try block and the finally block, the first one is propagated

Upvotes: -1

Related Questions