Sometime back a client asked me to put together a short write-up on my preferred Java exception handling approach, and I decided to capture this as a blog entry as well. Now exception handling is one of those controversial topics that has the Java world split on checked/unchecked exceptions, and I certainly have an opinion (or two) about it. So here come my opinions! 🙂
- Prefer unchecked versus checked exceptions in general
More often than not, clients are not in a position to handle exceptions, and either end up declaring all checked exceptions in their “throws” clause, or catching them generically and converting them into one “throws Exception” clause, or catching and converting them into a single “throws CustomCheckedException” clause. In none of these scenarios, do checked exceptions lend additional value. Checked exceptions do introduce some “versionability” issues – an earlier version of a method throws exceptions A and B, and now when you add new functionality to this method, it can encounter exception C which it cannot handle either; since checked exceptions are part of the interface, this method should not throw a checked exception C or else it breaks its contract with existing clients. Now you are stuck either converting C into an unchecked exception or modifying all clients – neither of these is a good option. Additionally with checked exceptions you can run into issues with needing to throw many exceptions because you cannot handle them within the method you are writing; once you get to a client that calls 3-4 methods each of which throw 3-4 exceptions each, you now have a client method that potentially needs to throw 12-15 exceptions – not good!
- If we encounter a checked exception in any code that we write, if we cannot handle the exception, we should in general convert the checked exception(s) from other libraries or base java libraries into an unchecked custom exception. If there is a possibility that a client may be able to do something useful with the exception, use a specific unchecked custom exception; if it is something that the client would not have a chance to do anything with, then make it a generic unchecked custom exception.
- Anytime we convert an exception, we should nest the underlying exception in the new exception.
- Never catch an exception and do nothing or do nothing except log the exception occurrence. If the proper way to handle an exception is to ignore it, that’s okay, but it should be clearly commented to ensure that you deliberated over this and consciously chose this option; do include your reasoning in your comment.
- Never reveal details of your implementation in your exceptions by throwing a checked exception that is specific to a library that you are using. By doing so, you can introduce clients that now have a dependency on a library that you use internally.
- Never display exception stack traces on a web page; in general favor a generic error message to the user for exceptions that bubble up to the “view”; log a more detailed error at the server level.
- Always use a common exception handler to ensure consistency in how exceptions are handled, and allowing us to add common functionality such as notifications/alerts as needed.
I can understand that you may not agree with some or any of this, and I am sure that if you have been around Java for some length of time, it is unlikely that I can sway your opinion! 🙂