What exactly gets into the 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 happens if both the code inside the try block and the automatic close() operator throw exceptions? Which one will fall into the catch ? Both of them? Only one of them? If so, which one?

Also, what if try successful, but close not? Will a catch block be introduced?

+6
source share
2 answers

Quote from the JLS section 14.20.3.1 :

In the core try-with-resources application managing a single resource:

  • If the resource initialization completes abruptly due to the throw value of V , then the try-with-resources statement unexpectedly terminates due to the throw value of V
  • If the initialization of the resource completes normally, and the try block completes abruptly due to the throw value of V , then:

    • If the automatic closure of the resource completes normally, then the try-with-resources statement completes abruptly due to the throw value of V

    • If automatic closure of a resource abruptly terminates due to the throw value of V2 , then the try-with-resources operator unexpectedly terminates due to the throw value of V with V2 added to the list of excluded exceptions of V

  • If the initialization of the resource completes normally, and the try block completes normally, and the automatic closure of the resource ends abruptly due to the throwing of the value of V , then the try-with-resources operator completes abruptly due to throwing the value of V

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

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


Here we check the verification of this behavior:

 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 

which means that the exception thrown for the exception was thrown by the try part for the code for the first part. For the second part, the exception clamped in the list was indeed the exception caused by close() .

+6
source

An exception thrown inside the try block is thrown into the outside world.

While when trying to catch, an exception thrown from the finally block will be propagated to 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 both in the try block and in the finally block (when the InputStream is closed), the latter is raised even if the exception thrown from the try block is likely to be more relevant for propagating.

 try(FileInputStream input = new FileInputStream("file.txt")) { int data = input.read(); while(data != -1){ System.out.print((char) data); data = input.read(); } } 

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

-1
source

All Articles