Java Exceptions Stuck To the Side of The Monitor

A security system only works if people are willing to use it. If the code for your burglar alarm is too hard to remember, you’ll simply never turn the thing on. If you are forced to use five or six cryptographically strong computer passwords on a daily basis, you’ll end up writing them on a post-it note stuck to the side of your monitor. Though technically instances of user non-compliance, these security breaches are really the fault of the system designers, who were so focused on hardening their creations against attack that they forgot to make them useful to the people they’re supposed to protect.

Java requires that you list all the exceptions that a method can throw in its prototype, plus all exceptions thrown by methods that method calls and so on. Failure to do so results in a compiler error. The motivation, as I understand it, is full disclosure: it is the job of a prototype to describe what a method returns, and sometimes what it returns is failure. Return values and exceptions are just different kinds of result. There is a formal elegance to this, but it misses a crucial social fact: program methods are not mathematical functions, whose domain and range are known a priori. They are flawed creations made by imperfect human beings whose capacity for error is a defining aspect of who they are. Even if at a certain level of abstraction there is no formal difference between an exception and a return value, there is a practical one, which is that a programmer can usually anticipate what their code will do right, but they can never anticipate all the things it might do wrong.

Exceptions are the way programming languages acknowledge this fact. They are syntactic embodiments of the element of surprise. C++, Python, and Ruby fully embrace surprise by allowing any part of the code to throw any exception at any time, no questions asked. Java starts from this point, but then adds the superfluous notion of exception-as-return value. This is classic over-design.

Like users of excessively restrictive security systems, Java programmers learn ways to work around the language’s syntactic overreach. Sometimes you get sick of trying to anticipate all the things that might go wrong in the future and put the top of the exception hierarchy into your method prototype.

public void method(int arg1, int arg2) throws Exception {
    // Something may go wrong here. That's life.
}

The throws Exception clause here discloses nothing. The only thing it tells me is that the code probably isn’t perfect, which I knew already. This is the equivalent of never turning the burglar alarm on.

The Java language itself provides a workaround by creating a confusing distinction between Runtime exceptions and…uh…non-Runtime exceptions. (I’m writing this in a café that doesn’t have wireless, so I can’t just go Google up the correct term, but my inability to remember it is itself telling.) This nomenclature is absurd. All exceptions are runtime exceptions, because they only get thrown when the program is running. (You don’t point to a broken computer sitting in the garbage and say, “The programs running on that machine threw five exceptions today.”) As is often the case, bad nomenclature is a sign of bad design. A better name for RuntimeException would be IgnoreThrowsClauseException. They’re essential for deriving from public interfaces. For example, recently I wrote a Hadoop mapper that parses some XML. The only way I can get it to compile is to employ an idiom like the following:

@Override
protected void map(Text key, Text xml, Context context) throws IOException, InterruptedException {
    try {
        // Parse XML in here.
    } catch (SAXException e) {
        throw new RuntimeException(e);
    } catch (XPathExpressionException e) {
        throw new RuntimeException(e);
    }
}

It doesn’t matter if you don’t know what Hadoop is. The point is that some person wrote a method called map with the intent that I should override it. That person did not include XML-related exceptions in the prototype because they did not anticipate that I would be parsing XML, which is entirely reasonable because we’ve never met. Now another human being who I’ve also never met wrote the XML, and they might have done it wrong. But the compiler won’t allow me to directly acknowledge all the problems that may arise in the course of our anonymous three-way collaboration. Instead I must hide XML-related errors inside a RuntimeException, like a truculent drunk being hustled out the back door.

There are three things wrong with this code. By Java’s own standards it is a failure because the method prototype does not list all the exceptions it throws: it tells you about the IOException and InterruptedException, but you have to read the method body to learn about the SAXException and the XPathExpressionException. Furthermore the catch clauses are utterly vacuous: visual clutter that serves no algorithmic purpose. In C++, Python, or Ruby you wouldn’t write these lines and the program would work exactly the same. Worst of all, it throws away information. I have to turn a specific XPathExpressionException object into a generic RuntimeException object. Java forces me to jump through hoops in order to ignore its own error hierarchy. The catch clauses I reluctantly added are the equivalent of a post-it note with passwords on it stuck to the side of the monitor.

Advertisements
This entry was posted in Those that have just broken the flower vase. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s