Tuesday, November 11, 2014

On Checked Exceptions in Java



Every year or so I get fed up with Checked Exceptions. I know the topic is controversial and has been raging for decades, but really, Java should just make them a compiler option or perhaps an annotation option. But that's never gonna happen. 

So...

The problem

The following links have a good discussion of the problem (from my biased view):


The short version:

  • Only a problem in Java, since no other language has them. (C# decided not to have them).
  • Seemed like a good idea when introduced.
  • But leads to loads of horrible code just to rethrow, swallow, or wrap.
  • 95% of time, the human operator of the system has to deal with the exceptional cases.
  • So may as well let exceptions bubble up the stack until logging and appropriate error message can be given to the user.
  • Checked Exceptions do not work with clean interfaces, since vast majority of exceptions are dependent on implementation details.
  • Doesn't work well with functional language features (Java 8 - not that I use any of that stuff (old dog and all that)).

A Work Around

Project Lombok is a Java library that messes with the compiler using annotations. It does a bunch of nice things to reduce boilerplate code. In particular is has the @SneakyThrows annotation. This lets a method avoid having to declare all the Exceptions it otherwise would (after the throws keyword). Hooray!

I also like the solution presented in http://james-iry.blogspot.com.au/2010/08/on-removing-java-checked-exceptions-by.html. The nice thing here is the ability to declare that a block of code can in fact throw a checked Exception, even if the Exception no longer appears on any of your method signatures (e.g. because of @SneakyThrows). This allows you to write catch blocks for those Checked Exceptions without running into compiler issues.

How do we use Exceptions?

What do we really want to log from an Exception?
  • Where the problem happened (stack trace, line numbers)
  • Category of exception (Type name, e.g NullPointerException)
  • Brief message containing other pertinent logging info (file names, memory, addresses, etc)
And in terms of handling an Exception we might also want to know:
  • does rollback need to happen (e.g. for a database)? how?
  • was it bad data that caused the exception, or was is environmental/resource?
  • can we try to call again soon? how soon?
Expressed in terms of 'concerns', Exception handling boils down to:
  • Logging (support guys)/Error messages (users)
  • Cleaning up, if any (handling code)
  • Re-trying (handling code)

Checked Exceptions are really "Expected Exceptions"


Suppose you are working on a large, mission critical system with lots of moving parts and complex interfaces that must all be coordinated together. Typically there would be many databases, web-services, file access, caches, etc that are interacting and must be marshaled carefully.

Some people would say "I need to know all the failure modes of each sub-system in  order to handle them correctly". I can understand this view. It strives for completeness and correctness, but there are couple of problems with it:
  1. Unchecked Exceptions can always crop up. These must be handled anyway.
  2. There are only a limited number of responses to failure. These responses may as well be gathered together in a few handlers.
The types of concerns listed in the previous section should be caught and handled for each of the interacting subsystems, rather than for each subsystems peculiar Exception classes.

Sure, there will be cases where special handling will be required for some Expected Exceptions. These should be part of the API, and should be quite rare. Perhaps a compiler warning, rather than an error?