and boy were they scaryBe aware: This is a post about checked exceptions. (And of questionable coherency, as well.)

In my experience – which I eventually, painstakingly, finally gathered – checked exceptions aren’t pulling their weight. In fact, they are downright harmful. But explaining why is really hard, or so it seems. It must be, since so many have tried and still it hasn’t sunk in.

Everyone has been through all the basics (declare or re-throw, and so on) so I will assume intimate familiarity with Java exceptions and go right to the code. I want to draw attention to Java’s InputStream, which defines a set of methods with well-documented contracts that subclasses and clients should adhere to. All in all, this is a decent object-oriented design.

Here is some code I found myself writing the other day:

private InputStream stream(String... args) {
  Properties props = prop(args);
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  try {
    props.store(baos, "Foobar");
  } catch (IOException e) {
    throw new RuntimeException("You're kidding me", e);
  }
  try {
    baos.flush();
  } catch (IOException e) {
    throw new RuntimeException
      ("OK, the computers are rebelling. Break out the canned " +
       "food, run for the hills", e);
  }
  return new ByteArrayInputStream(baos.toByteArray());
}

This method takes a sequence of strings and returns a corresponding stream, which will behave as if it were a properties file in the classpath.

Assuming I usually provide serious exception messages: Why the less-than-serious exception messages here? First of all, this is test code, so I’ve taken liberties. Second: As everyone can see, these exceptions won’t happen! In-memory arrays, which are in play here, aren’t subject to network conditions, slow I/O, packet loss and and other famous fallacies. If they do give you problems, you’re probably running on a seriously broken machine (or the AIs are turning on us). A silly test failing is probably not your priority.

Obvious conclusion: Catching exceptions here is silly, but we have to do it because they’re checked. ByteArrayOutputStream inherits all the methods from InputStream and they inherit their throwses as well. One remedy is that Java allows you to override methods and trim the throws list for things that don’t make sense to you. This is done by write in ByteArrayOutputStream, for instance, which omits theIOException.

However, clients that want to use the throws-free subclass signature will need a reference typed to the subclass, since the write method defined in InputStream still has the throws declaration. This breaks with the idea of polymorphism, and it bites us when we pass the stream to the store method, which quite rightly takes the obligatory InputStream. Only the caller knows the exception is bogus in this case.

Back in the method, next we call flush. ByteArrayOutputStream inherits this method implementation from its superclass, with throws lists intact. In this case, the default implementation is empty. It is thus redundant to call it, but it’s also common practice because it’s part of the general stream contract. All in all, it’s responsible client behavior to follow the contract, as the implementation might change but the contract will not. The end result is silly on in many ways: A dutiful client invoking an inert object, handling the fictitious exceptions because the subclass didn’t put in this silly override:

@Override
public void flush() {
// Override just to get rid of IOException - bonkers
}

I like to think that someone in Sun once wrote this method, and then erased it in deep denial of the silliness of it all. Anyway, as we’ve already been over: This wouldn’t have helped much once the object got passed around to other methods, typed to InputStream.

The last line is, so the speak, the exception that proves the silliness of the rules: For getting the byte array out of the stream, you call a method defined in the subclass. Naturally, it doesn’t throw any exceptions. It. Will. Just. Work. Just like all the other interaction with this instance of InputStream. Will. Just. Work.

This instance. It works, and I know it. And I think that is the real issue.

Programming is a conversation between the creative, human programmer and a rigid, formal system. The question for the programmer is: What rigid, formal system am I talking to? Am I working with the runtime instance of InputStream, or am I working with the statically defined interface InputStream? Am I in a conversation with the runtime, or the compiler?

Having worked with interactive systems like Smalltalk, my mindset is that talking to the runtime is just as important as talking to the compiler. Programming, by its nature, is to dictate ahead of time what should happen in any given instance of your program. However, you should remember that in the future, there will be more information available. In particular, there is all the information that you have gone out of your way to hide from yourself. At the programming stage, you should hide it. It’s good, sensible, object-oriented design to hide information, encapsulate knowledge and say “this class should know this but not that” and “only this class should know this”. It’s not a good idea to hide runtime knowledge that the objects will have as a result.

In order to evolve and refine your code, you need that feedback from the runtime. At programming time, there are references of type InputStream. But at runtime, there are no instances of InputStream as such. They are all objects of a more specific type, and that is what you need to talk about, to get your program in shape.

In this case, checked exceptions get in my way so I can’t say “this method knows that this is a safe, in-memory operation”. I can’t tell that to the Properties instance, so it has to assume the worst and project that back on me: OK, I’ll take your little input stream – but I know those things aren’t generally trustworthy, so you have to handle this exception.

Checked exceptions, to me, are firmly in talk-to-the-compiler country. I think it’s hurting people’s ability to talk to the runtime, and thus it is harmful. People seem to spend so much of their time typing those throws and catches. Here is some code that can result:

try {
  Query query = readFromStream(stream, encoding)
  return process(query, settings);
} catch (FooException e) {
  throw new MyException("There was a foo problem", e)
} catch(BarException e) {
  throw new MyException("Bar failure detected!", e)
} catch(ZotException e) {
  throw new MyException("Zot exception", e)
}

If you talk mostly to the compiler, this can be quite sensible code. (It even preserves the cause, which is more than I can say for certain open source frameworks.)  You catch what you have to catch, then you do the rethrows to comply with your own throws. My suggestion would be:

Query query;
try {
  Query query = readFromStream(stream, encoding);
} catch (Exception e) {
  throw new MyException(this + " failed to read query from " +
     stream + " with encoding " + encoding, e);
} // the above could be a method, really
try {
  return process(query, settings);
} catch (Exception e) {
  throw new MyException(this + " failed to process " + query +
    " with settings " + settings + ", query source: " +
    stream, e);
}

The main difference is that information from the execution context is preserved, instead of the code just repeating information that is available from looking at the code. All exceptions are handled the same, avoiding duplicaton of the code that builds the message and encouraging us to refine this code further. We don’t need to mention any of the Foo, Bar and Zot trio of error cases explicitly, because that will be apparent from the wrapped exception. When I look at the stack trace later, the fact that the compiler and the programmer knew about the exception type beforehand is of limited utility. What I need to know is what the code was actually trying to do, and what went wrong – whatever it was.

It could be that the code was trying to do something completely out of whack. Is this what programmers are afraid to reveal? Is it more comforting to say “oh, I definitely know that this exception might occur – it’s declared!” and handle the error in a way that lets the world know they really understand how this checked exception thing works? Giving the future and the runtime their say in it may be scary – like losing control. Yet it is when things are completely out of whack that we need to know what those things are.

By the way, I assume sensible toString()s that get invoked when this and query are included in the message. The stream isn’t likely to have a meaningful string representation, unfortunately, but we should act as if it someday will.

Some might balk at the catch-all of Exception. I consider in an improvement here, since it will provide more information with less maintenance. It also tells us something slightly different about the code. Specific catches makes me suspect that the programmer has been forced to type out the different cases by the compiler, and really has no idea what they mean, outside of what their Javadocs say. Having a single catch-all clause, however, can be interpreted as a sign of life. It tells me that the programmer is aware that this spot is an important cog wheel in the program flow. It is important to preserve information about the failure if any exception travels through this spot, especially if it was an exception we didn’t expect – an actual exception.

Of course, it’s OK to add specific catches if we know their significance. We might know that this exception definitely indicates that error condition, and we want to act on that. However, this knowledge has to be maintained. A generic catch-all with sufficient information capture could serve you equally well, at least until your runtime world has stabilized. Until then, error handling is a moving target and the priority should be to get a feedback loop working, to help you gradually understand your code base and runtime fully.

This applies to log messages as well – there is a world of difference between:

public void doStuff(String stuff) {
  log.info("Now doing stuff")

and

public void doStuff(String stuff) {
  log.info(this + " now doing " + stuff)

Again, remember to put in a good toString() to reveal essential instance state.

If you talk only to the compiler, you will tend to type in what you knew when you typed it in, ie.: “Yeah, we expect Foo, and Bar, and Zot to be the unexpected outcomes here – the compiler told me that”. If you talk to the the runtime also, it is natural to just ask it to provide any and all information relevant to future error analysis. I think much code would be improved if more programmers were on talking terms with both the compiler and the runtime. And if they talked to the runtime more, they would realize that the runtime is where all exceptions come from – from the future! All exceptions are really runtime exceptions.

As is wont to happen now and again, the other day I received an IllegalArgumentException. Dragging my carcass down the dusty stacktrace, I find the culprit:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();

Oh boy. That makes me mad. (This actually happened weeks ago, I just now calmed down enough to write this.)

We are looking at a constructor, and we are looking at years of wasted time for mankind. Java is now thankfully open source, but this is a cause of the closed runtime syndrome, being the term I’ve decided to rant about in this post.

In all fairness, this code isn’t half bad. If you detect an illegal argument, you should throw an exception instead of continuing. Argument checking and failing fast are wise practices. But one important aspect is not handled here: Revealing which argument was the illegal one, and why. It’s not like it’s difficult; this would be enough:

    throw new IllegalArgumentException(corePoolSize + "/" +
        maximumPoolSize + "/" +
        keepAliveTime)

Using the source and the actual exception, this gives me more clues about what’s going on, without having to pull out my debugger. But we can still take another big step in the right direction. What if we were to get this information from just the exception, without the need to consult the source? Sounds utopian, but it turns out to be quite straightforward. Here’s an example:

    throw new IllegalArgumentException
        ("corePoolSize: " + corePoolSize)

Of course, this involves dividing up the checks and throwing custom exceptions for each illegal input. Preferrably, the exception should list all illegal inputs detected. Actual error handling logic now: More work for the programmer!

More work it is. A hell of a lot of work, actually, like all things code-related. But I think this is an important complement to open source – the open runtime! The closed runtime simply throws an exception (at best). Working with closed runtimes are just as inconvenient as closed source, and given the choice, I’m not so sure I would choose the open source every time.

The open runtime, on the other hand, consciously goes about telling you what’s wrong, instead of hiding it – it considers the task of assembling and emitting error information an important part of its logic.

Maintaining an open runtime is the responsibility of all code loaded into the VM; the application, the libraries, the framework(s). And yes, the standard library as well. The Java object system provides one vital component: exceptions with messages. Equally important is the facility of exception chaining, which I won’t go into here – just do it. However, the third component is often overlooked: The Object toString() method.

Implementing a sensible toString is about the best thing you can do for prosperity, world peace a close second. It means everyone can benefit from using your object in exception messages, as well as log messages. It means every log message and exception they appear in will become a little more informative. If you provide a library used by many, the benefits are boundless. You know a good toString method when you see its output: It tends to describe important state (for value objects) and/or identity (for entities). Important state here being e.g. the factors that determine how the instance will behave, or what its logical meaning is. (If any.)

So everyone has the responsibility of opening up the runtime, and the further “down” you tend to be, the bigger your responsibility. It’s a trickle-up effect! What would the world be like if an int presented itself as e.g. java.lang.Integer@123123? A lot more difficult to debug, for one thing. Such transparency makes more or less sense for all objects, especially if they are in heavy rotation. So, if they end up in a log message or an exception message, they contribute by adding meaning to it – every time. Adding a toString is a lot better for your karma than not, which is basically like being a time-sucking vampire. A closed runtime sucks time and energy from all who touch it, from fellow developers to IT staff who have to keep it running.

The Java standard library should definitely know its role in making Java runtimes more open. But e.g. ThreadPoolExecutor doesn’t implement toString – how many man-years have been lost to debugging because of that? (It’s not that I want to know, I was going for rhetorical.)

To sum up: Just implement toString sensibly, assemble enlightening exception messages, and always wrap the cause. Afterwards, the world is a little better, your runtime (and possibly others) will be more transparent and less closed, and everyone has more time to write code, because they don’t have to dig around in a debugger to find out what the hell is making your code scream. And, bonus, you won’t see your code in my blog, I promise.