Reputation: 882
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
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 valueV
, then the try-with-resources statement completes abruptly because of athrow
of the valueV
.If the initialization of the resource completes normally, and the
try
block completes abruptly because of athrow
of a valueV
, then:
If the automatic closing of the resource completes normally, then the try-with-resources statement completes abruptly because of a
throw
of the valueV
.If the automatic closing of the resource completes abruptly because of a
throw
of a valueV2
, then the try-with-resources statement completes abruptly because of athrow
of valueV
withV2
added to the suppressed exception list ofV
.- 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 valueV
, then the try-with-resources statement completes abruptly because of athrow
of the valueV
.
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
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