Home  Exceptions  try/catch  finally  Throwing  Exception hierarchy  Unchecked exceptions  Exception recasting  Uncaught exceptions

Exceptions: the finally block

In our explanation of the try/catch block we mentioned the issue that we needed to ensure that a file was closed whether or not an exception occurred. Java provides an extension to the try/catch block for such an eventuality. We can use the following structure:

try {
  ...
} catch (IOException ioex) {
  ...
} finally {
  ...
}

With this structure, the code in the finally block will always be executed whether or not an exception occurs within the given try block. So we can put "cleanup" code such as closing a file inside the finally block. We actually don't need a catch block with the finally: we can still let exceptions be passed up to the caller. In this case, we end up with a try/finally block. For example, our method to read a number from a file can look like something this:

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 {
    br.close();
  }
}

What if an exception occurs in the finally block?

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

Next...

Next, it is recommended that you take a look at our discussion of the exception hierarchy, which also looks at the difference between what are called checked and unchecked exceptions.


1. The unlikely cases where this would happen include closing network sockets, where a final 'handshake' occurs across the network to close the connection, and potentially when updating metadata (last access date etc) of a file on disk. But in either case, your program would by that time have the data it needed, so probably wouldn't care terribly about the error.

comments powered by Disqus

Unless otherwise stated, the Java programming articles and tutorials on this site are written by Neil Coffey. Suggestions are always welcome if you wish to suggest topics for Java tutorials or programming articles, or if you simply have a programming question that you would like to see answered on this site. Most topics will be considered. But in particular, the site aims to provide tutorials and information on topics that aren't well covered elsewhere, or on Java performance information that is poorly described or understood. Suggestions may be made via the Javamex blog (see the site's front page for details).
Copyright © Javamex UK 2009. All rights reserved.
Search this site:
Threads Database Profiling Regular expressions Random numbers Compression Exceptions C Equivalents in Java

 What do you think of this article? Did it help you? Found a mistake? Feedback and suggestions here