Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 368
Enrique Avatar asked Jan 15 '16 14:01

Enrique


People also ask

What is true regarding the try with resources statement?

The try -with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try -with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.

What happens if try with resources throws an exception?

For try-with-resources, if an exception is thrown in a try block and in a try-with-resources statement, then the method returns the exception thrown in the try block. The exceptions thrown by try-with-resources are suppressed, i.e. we can say that try-with-resources block throws suppressed exceptions.

Is catch block mandatory for try with resources?

This the catch is optional because readLine() doesn't throw a (checked) exception. Yes, close() could throw an exception, but the try-with-resources handles that too. So this try-with-resources doesn't need a catch.

Which of the following is correct statement about try with resources statement in Java 9?

The try-with-resources statement is a try statement with one or more resources duly declared. Here resource is an object which should be closed once it is no more required. The try-with-resources statement ensures that each resource is closed after the requirement finishes.


1 Answers

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().

like image 177
Tunaki Avatar answered Oct 12 '22 05:10

Tunaki