The try-finally and try-catch-finally statements
suggest changeThe try...catch...finally
statement combines exception handling with clean-up code. The finally
block contains code that will be executed in all circumstances. This makes them suitable for resource management, and other kinds of cleanup.
Try-finally
Here is an example of the simpler (try...finally
) form:
try {
doSomething();
} finally {
cleanUp();
}
The behavior of the try...finally
is as follows:
- The code in the
try
block is executed. - If no exception was thrown in the
try
block:
- The code in the `finally` block is executed.
- If the `finally` block throws an exception, that exception is propagated.
- Otherwise, control passes to the next statement after the `try...finally`.
- If an exception was thrown in the try block:
- The code in the `finally` block is executed.
- If the `finally` block throws an exception, that exception is propagated.
- Otherwise, the original exception continues to propagate.
The code within finally
block will always be executed. (The only exceptions are if System.exit(int)
is called, or if the JVM panics.) Thus a finally
block is the correct place code that always needs to be executed; e.g. closing files and other resources or releasing locks.
try-catch-finally
Our second example shows how catch
and finally
can be used together. It also illustrates that cleaning up resources is not straightforward.
// This code snippet writes the first line of a file to a string
String result = null;
Reader reader = null;
try {
reader = new BufferedReader(new FileReader(fileName));
result = reader.readLine();
} catch (IOException ex) {
Logger.getLogger.warn("Unexpected IO error", ex); // logging the exception
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
// ignore / discard this exception
}
}
}
The complete set of (hypothetical) behaviors of try...catch...finally
in this example are too complicated to describe here. The simple version is that the code in the finally
block will always be executed.
Looking at this from the perspective of resource management:
- We declare the “resource” (i.e.
reader
variable) before thetry
block so that it will be in scope for thefinally
block. - By putting the
new FileReader(...)
, thecatch
is able to handle anyIOError
exception from thrown when opening the file. - We need a
reader.close()
in thefinally
block because there are some exception paths that we cannot intercept either in thetry
block or incatch
block. - However, since an exception might have been thrown before
reader
was initialized, we also need an explicitnull
test. - Finally, the
reader.close()
call might (hypothetically) throw an exception. We don’t care about that, but if we don’t catch the exception at source, we would need to deal with it further up the call stack.
Java 7 and later provide an alternative try-with-resources syntax which significantly simplifies resource clean-up.