Back to Error Prone

Finally

docs/bugpattern/Finally.md

2.49.01.5 KB
Original Source

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.

java
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.

java
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.

java
Closer closer = Closer.create();
try {
  InputStream in = closer.register(openInputStream());
  doWork(in);
} catch (Throwable e) {
  throw closer.rethrow(e);
} finally {
  closer.close();
}