| 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](https://guava.dev/releases/snapshot/api/docs/com/google/common/io/Closer.html). | |
| ```java | |
| Closer closer = Closer.create(); | |
| try { | |
| InputStream in = closer.register(openInputStream()); | |
| doWork(in); | |
| } catch (Throwable e) { | |
| throw closer.rethrow(e); | |
| } finally { | |
| closer.close(); | |
| } | |
| ``` |