Exceptions: when to catch and when to throw?

Adding a throws declaration to a method allows us to 'pass the buck' and make the caller to our method deal with the exception. Part of good program design in Java involves deciding when it is appropriate to catch and deal with exceptions directly, and when it's more appropriate to throw them back to the caller. The questions are often: can my method sensibly take appropriate action, or does that action need to be taken by the caller? And: does the caller need to know that an exception occurred?

Don't turn an exception into a return value

A good indication that you're catching the exception in the wrong place is if you end up writing code like this:

public int readNumberFromFile(File f) {
  try {
    ...
  } catch (IOException ioex) {
    return -1;
  }
}

This is bad for all the reasons that error handling in C was bad: you put the onus on the caller to remember to check for the error value; you remove the possibility of using that particular value as a genuine "value" (i.e. our file now can't contain the number -1); you make it clumsy for the caller to find out information about the error; and if the caller in turn can't handle the error immediately, then they have to resort to some similar tactic for notifying their caller (and at that point, for the caller of the caller to find out more details about the error is going to involve some particularly klutzy program flow).

Don't swallow exceptions

Another favourite among some programmers appears to be to "swallow" an exception and make the program carry on regardless, as though "nothing happened":

private String line = null;

public void populateLine(BufferedReader br) {
  try {
    this.line = br.readLine();
  } catch (IOException ioex) {
    // maybe log the error in some unuseful place but
    // whatever we do don't let the caller know there
    // was a problem...
  }
}

A caller to populateLine() will be expecting the line variable to be populated with a line from the file. If this isn't possible, the above method simply pretends that nothing happened. Later on in time, some part of the program will try to access the line method, and you'll probably end up with a spurious NullPointerException whose cause will be more difficult to track down.

So in general: if an exception occurs, there's usually no benefit in pretending it didn't. If your method can't deal with it, that's usually a good sign that you need to throw it up to the caller.

So when to catch...?

In case you think we've painted a negative picture of catching exceptions, there are of course cases where it is appropriate to catch the exception. (After all, it has to be caught somewhere eventually...) Typically, exceptions are caught in places where:

An example of the last case would be a routine that took lines of input from a file, but knew that occasionally a line would be malformed. The routine might want to ignore the malformed lines (although presumably still log them in some way) and still process the good ones, rather than rejecting 100,000 lines of data because of 3 malformed items.

There are also a few cases where we're forced to deal with an exception (because Java makes us) in cases where we really don't expect the exception to occur. For example, we really wouldn't expect a ClassNotFoundException to occur while deserialising a String, but Java forces us to worry about handling such a case.