An issue for which there's no really neat solution is that code in the finally block could itself throw an exception. In this case, the exception in the finally block would be thrown from the exception instead of any exception occurring inside the try block. Since code in the finally block is intended to be "cleanup" code, we could decide to treat exceptions occurring there as secondary, and to put an explicit catch:
public int readNumber(File f) throws IOException, NumberFormatException {
BufferedReader br = new BufferedReader(new
InputStreamReader(new FileInputStream(f), "ASCII"));
try {
return Integer.parseInt(br.readLine());
} finally {
try { br.close(); } catch (IOException e) {
// possibly log e
}
}
}
We might often choose to at least log the exception. In the case of an exception occurring while closing an input stream1, this is one of the few cases where it's fairly legitimate to just ignore the exception, or else take the risk that it will override the main exception. (If you log the exception to somewhere, then you would have a chance of catching cases where your logic was wrong and an exception during closure turned out to be significant for some reason.) For something as unlikely as an exception while closing an input stream, "taking the risk" is generally my preferred solution, favouring more succinct code.
More care needs to be taken during closure of an output stream, since in this case pending data may actually be written before closure and an "important" error is more likely. For different reasons, we may actually arrive at the same code pattern: since data is potentially being written, we probably would allow an exception on closure to be propagated by the method. The 'overriding' exception in the finally clause is still likely to indicate the underlying cause of the initial exception.
Some other things to note about finally blocks:
The same 'overriding' problem that we mentioned with exceptions occurs when returning a value from a finally block: this would override any return value that the code in the try block wanted to return. In practice, returning a value from a finally clause is rare and not recommended.
Actually exiting the program (either by calling System.exit() or by causing a fatal error that causes the process to abort: sometimes referred to informally as a "hotspot" or "Dr Watson" in Windows) will prevent your finally block from being executed!
There's nothing to stop us nesting try/catch/finally blocks (for example, putting a try/finally block inside a try/catch block, or vice versa), and it's not such an uncommon thing to do.
No comments:
Post a Comment