I was just having yet another read of yet another programmer's opinion on how to handle exceptions, ie whether API writers should throw checked exceptions, or just unchecked. -
I've been in a dilemma about this for years and keep hoping that some day someone will figure out a satisfactory answer.
There's certainly no shortage of opinions, but none that i've seen actually translate into programming practise which, when applied to real world scenarios, gives a good result. So here's my take...
Firstly, some things that everyone can agree on..
- Definition: An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions. (from sun)
- Unchecked exceptions are for program errors. A program can't very well handle a program error, since by definition its not expected.
- Checked exceptions are to indicate specific domain conditions. IOException for files, SQLException for databases, CustomerDoesNotExist for some system with customers, LoginException for when a login attempt fails, etc.
Hang on a second!
Isn't login failure normal for a login module? Isn't it normal to sometimes not find a customer? Isn't it normal for a file to not exist? Yes, of course these are normal conditions, and code which uses functions to login, find a customer and open a file will need to check for these conditions, because they're normal.
But if they're normal, then they are not exceptional. Ie they should not be represented by exceptions. Instead, they should be an explicit part of the method call.
| Exception based programming | Explicit methods | |
| Login Module | void login(String name, String pwd) throws LoginException | User login(String name, String pwd) |
| Customer Module | Customer findCustomer(String code) throws CustomerDoesNotExistException | Customer findCustomer(String code) |
In the first example, above, the exception based approach is to assume the method will succeed and throw an exception otherwise. The more explicit approach is to not assume anything. The method will return a user if the login is successful, otherwise it will return null. If more information is needed, such as the reason for a login failure, then a value object can be returned which may include a customer object and a message.
The last couple of years i've done a lot of work in teams made up of native born java developers as well former main frame and oracle developers, now reskilled as java developers. One thing i've noticed is that the former main frame guys tend to program much more explicitly and as a result their code is much easier to follow and maintain, then the supposedly hotshot java dudes.
But there are cases that warrant a checked exception. Like...um, can't think of any at the moment. But i have come across them. Usually when the exceptional conditions can be generated down deep in business logic, such as missing coded values or inconsistent data, and detailed information needs to be passed back to the user so they can correct the situation.
So my suggested approach is this:
- if there's a program error throw a RuntimeException. Add context if you can
- if your code has an exit condition which is important for client code to know, put it in the method call as a return value. Sometimes you need to return several pieces of information - don't be shy about using little tiny inner classes as value objects for this.
- If your code has an exit condition which really is exceptional, and should be handled but is not really a normal event, use a checked exception. If you're building an API which is truly reusable (not just the usual best-practise-everything-must-be-reusable bollocks) then you'll find this occurs more often.
Anyone care to comment? Oh thats right, I haven't built a comments component yet...