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

Exceptions: the try/catch block

In our introduction to exceptions, we showed how an exception object thrown by a method (in fact a constructor in the example) could be caught by the caller in a construction commonly called the try/catch block. In the block preceded by try, we put the code whose exceptions we want or need to trap. In the block preceded by catch, we put the code that will be executed if and only if an exception of the given type is thrown. Let's expand on this construction here. Firstly, we didn't explicitly state the following:

  • The try and catch blocks can contain arbitrary number of lines of code: in other words, with a single block, we can catch exceptions over a whole section of code. This makes things much more succinct than the traditional check for an error condition after every line typical in C programming.
  • So long as at least one of the lines in the try block can throw an exception of the given type, we can have other lines in the same block which don't actually throw the given exception.
  • We can have multiple catch blocks associated with a single try block, to catch different types of exceptions.

As an illustration of these points, consider the following code, which opens a file, reads a line from it, and parses the line. In this example, the first line of the try block can throw a FileNotFoundException and some of the later lines can throw an IOException. Additionally, there is one line that can throw a NumberFormatException. The call to line.trim() can't actually throw any of these exceptions, but it doesn't matter: we can still include it in the same try block to avoid having to make our code messy with multiple try/catch blocks. Notice how we can even put the return statement to the method inside the try/catch block. (It's important to state that this is an example of the points mentioned so far: in reality, there are other changes we'd need to make to this code, as discussed below.)

public int getNumber(File f) {
  try {
    FileInputStream fin = new FileInputStream(f);
    BufferedReader br = new BufferedReader(new InputStreamReader(fin), "ASCII");
    String line = br.readLine();
    line = line.trim();
    int number = Integer.parseInt(line);
    br.close();
    return number;
  } catch (FileNotFoundException fnf) {
    // Oh dear, error occurred opening file
    displayErrorMessage(fnf.getMessage());
  } catch (IOException ioex) {
    displayErrorMessage(ioex.getMessage());
  } catch (NumberFormatException nfe) {
    displayErrorMessage("The file contained invalid data");
  }
  return -1; // If we get here, we didn't read a
             // number from the file
}

(Note: we're not going to get bogged down in the actual calls to perform the I/O; to learn more about things such as the BufferedReader and the readLine() method, see this site's separate introduction to I/O in Java.)

Problems with this example (and how to resolve them)

Now, there are actually still some inconveniences with the above example that we'd need to resolve:

  • in the case of every exception, we're actually logging the error there and then; in reality, we might not want to mix file handling and user interface code in utility methods in this way; it would better to let the caller handle the error and manage things such as UI messages;
  • on a related issue, we're actually still returning a spurious value from our method when an error occurs: astute readers will recall that one of the whole points of exceptions was to properly separate return values from error states;
  • if an exception occurred after the file was created, we woudldn't close the file.

It turns out that there's also no need for us to handle FileNotFoundException and IOException separately (unless we really want to). This is because FileNotFoundException is actually an extension (subclass) of IOException. So just catching or handling IOException is enough to cover both cases.

On the next pages, we'll look at how to resolve these problems:

  • using a throws declaration, we can make our method throw exceptions 'back up' to the caller for the caller to handle rather than having to handle them there and then;
  • we can use a finally block to make sure the file is closed whether an exception occurs or not.
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