We had an internal discussion recently on checked versus unchecked exceptions somewhat mirroring Howard Lewis Ship’s recent commentary on the subject. The discussion was about a library that throws a `RuntimeException` in cases where the client programmers really should be handling the situation – there is some predictable error case and the client _can and should_ handle it. There was heated argument that this should therefore be a _checked exception_ – I am not a fan of checked exceptions and suggested alternatives.

Now, Java is almost the only language that actually supports checked exceptions. Even in Java they are many who consider them _A Bad Idea™_ that should be avoided. Why? Because they are still exceptions – designed for exceptional circumstances – and using them for control flow just isn’t good programming[1]. Checked exceptions force the client code to deal with the exceptional case using clumsy constructs and are generally so un-user-friendly that the most common way of handling them is to catch then call `ex.printStacktrace()`​ which is actually _the worst possible thing to do_! The ever increasing use of alternate languages on the JVM means that exceptions are absent in any other language that needs to interop with your Java API anyway.

There are further ways in which exceptions are just not _ergonomic_. Exceptions do compose reasonably well, but exception ergonomics are not just about the compositional semantics. There is no possibility of contravariance in an exception signature for instance (so you have to either have `throws Exception​` (eg. `Callable.call()`​) which is meaningless and defeats the whole point – or you have parametric exceptions (which I have never seen actually used). While you can​ have covariant exception signatures they aren’t very useful in practice either. One of the major reasons the closure proposal has been delayed so much is the complexities thrown up by checked exceptions. Lastly, an API with a checked exception in it is stunningly hard to modify and maintain source backwards-compatibility. Your only chance is if you have parameterised your exception type (again, see closure proposal discussions for how well _that_ works)​.

So given how bad they are, what are our alternatives?

For instance if you have the following signature:

/** Get the numeric value contained in the parameter **/
Integer parse(String) throws NumberFormatException

How do we make this handle cases where the input isn’t made solely of digits without throwing exceptions? We could return `null`? bzzzzt! Back of the class. Nulls are very, very bad, and encoding null with any sort of meaning (in this case that the input was unparsable) is terrible. Nulls are attractive in that null is always a member of any reference type, but they lead to all sorts of problems – not the least being the dreaded `NullPointerException`. So, no nulls and no exceptions, where do we go next?

A good first effort is to use an `Option`​ or `Maybe`​ type, where the possible results are `Some`​ number or `None`​. This is how it looks now:

/** Get Some numeric value from the parameter, or None */
Option parse(String);

This is quite a lot better than null as the result is definitely not null and can have lots of useful functions on it for dealing with the result if present, but it doesn’t really deal with the failure case very well. Ie. what happened if I get a `None​`? Why did it not parse?

In this case what we want is something like an `Either` (technically a disjoint union). This fairly straight-forward type represents _either_ an `X​` or an `A`​. By convention the `X`​ (left) is for problems/exceptions and the `A`​ (right) is for the expected result as it is the _right_ side.

/**
* Get either a numeric value from the parameter,
* or a NumberFormatValidation explaining what was wrong
*/
Either parse(String);

Now we have a more honest result type. It tells you that it will definitely for each and every `String` return you something, either the `Integer` value or a `NumberFormatValidation` (or an `ErrorMessage`, or an error `String` or whatever). There is no `null` to deal with anywhere and no ugly catch blocks.

Furthermore, as the actual type if the lhs is not restricted to subclasses of `Exception`, the opportunity to use it for carrying data is much broader. Subclassing `Exception` to allow carrying of data (such as `ValidationException` or some-such) has been clumsy at best in practice. With `Either` we can use any structure to represent failure at all.

Java doesn’t make using these things syntactically much nicer than using checked exceptions (that is a general problem with Java) but there are enough benefits to seriously consider these techniques as significant alternatives even in a pure Java project.

Whether or not you use these features directly, you are likely to come across more and more code that uses them as the state of the art moves on.

[1]: There are of course specialised [ahem] exceptions to this rule but we’ll ignore that for now.