I was wondering why the program was failing silently. Eventually I tracked it down to this:
} catch (Exception e) { return null; }
Argh! I understand that whoever wrote this probably does not intend harm, but it does no favours to any programmers who are trying to fix problems later.
I suspect this is a case of the law of unintended consequences, as discussed by Bruce Eckel amongst others. Exceptions that a programmer must declare or handle should encourage discipline and careful design. However, given human nature and the pressure to get things done, it's too easy to write a catch clause that just ignores the problem.
Note to self: no matter how unlikely I think some scenario is, I must never just swallow an exception.
Here's what I should do, from best to worst.
- Avoid the exception altogether.
- Mainly, this means designing the program so that users cannot go down a path where they will trip. There is a danger that power users might feel constrained, but in any case the obvious actions should not lead to errors. It's hard to guide users when the program has to interact with an external environment over which the programmer has no control.
- Fix the problem automatically without making a fuss
- It's tempting as a programmer to highlight how clever the code is to be able to recover; it's usually best to resist the urge.
- Report the error
- Again, the program should not make too much fuss. If the program is utterly stuck and there is no way to get anything to work, a prominent error message is appropriate. If there's a minor glitch, a subtler and less intrusive message may be called for.
- Log the error
- The much maligned System.err.println() has its uses. At the very least it gives a programmer something to grep for. With Java there are at least a couple of decent choices for logging.
As a user, I want to know if something went wrong. A program that fails silently is worse than one that fails with a cryptic error message.
As a programmer, I want to know what went wrong. It doesn't matter if I can't immediately figure out what it is: I just want enough to point me to the right place to look in the code.
In case you haven't seen it before, Joel Spolsky has a whole discussion about exceptions and error handling:
http://www.joelonsoftware.com/items/2003/10/13.html
Yes, I remember seeing Joel's piece and, like many people (for example, Charles Miller at http://fishbowl.pastiche.org/2003/10/14/taking_exception_to_joel_spolsky and Sean Corfield at http://www.corfield.org/blog/past/2003_10.html#000142),
I think he's mostly mistaken.
Return codes in C are easy to ignore: there's no need even to write a catch clause. As Joel himself admits, checking every damn return code is a pain and obfuscates the point of the code. I've had to debug C code like that and that is no more fun, especially when return codes are checked most, but not all, of the time.
I particularly like one of Sean's points: if I use exceptions, I can let them percolate all the way to the top level (where they can be reported and/or logged). That makes sense for can't-happen or can't-fix scenarios. It's true that I could cobble something together with return codes that would have a similar effect; however it's much harder to do that without introducing extra dependencies and making it all more fragile as a result.