Alternate names: finally, ThrowFromFinallyBlock
Terminating a finally block abruptly preempts the outcome of the try and catch blocks, and will cause the result of any previously executed return or throw statements to be ignored. Finally blocks should be written so they always complete normally.
Consider the following code. In the case where doWork
throws SomeException
,
the finally block will still be executed. If closing the input stream also
fails, then the exception that was thrown in the catch block will be preempted
by the exception thrown by close()
, and the first exception will be lost.
InputStream in = openInputStream();
try {
doWork(in);
} catch (SomeException e) {
throw new SomeError(e);
} finally {
in.close(); // exception could be thrown here
}
This code is easily fixed using try-with-resources. Below, the input stream will
always be closed, and if doWork
fails and an IOException
is thrown, then the
try-with-resources uses the Throwable.addSuppressed()
method added in Java 7
to propagate both exceptions back to the caller.
try (InputStream in = openInputStream()) {
doWork(in);
} catch (SomeException e) {
throw new SomeError(e);
}
If Java 7 is not available, we recommend Guava’s Closer API.
Closer closer = Closer.create();
try {
InputStream in = closer.register(openInputStream());
doWork(in);
} catch (Throwable e) {
throw closer.rethrow(e);
} finally {
closer.close();
}
Suppress false positives by adding the suppression annotation @SuppressWarnings("Finally")
to the enclosing element.