{ by david linsin }

July 06, 2009

When Unchecked Exceptions Go Wrong

In the application I'm developing right now, we found a bug right before going live. A colleague of mine forgot to catch an unchecked Exception in a loop, which led the loop to exit, before iterating over each element. Bugs like this are so subtle and hard to track, that's why I think it was kind of my fault for not using a checked instead of an unchecked Exception.

// must work all jobs
private void workAllJobs() {
for(MyJob job : allJobs) {
job.work(); // throws RuntimeException
}
}

Let me be clear, I don't want to engage into the checked vs. unchecked Exception war. I made my point clear a couple of times, however I simply think I need to revise my position.

I used to think forcing a client of an API to catch an Exception was evil! That's why I usually design custom Exceptions to inherit from RuntimeException and declare each and every case carefully in the javadocs of my API methods. I simply followed the expert's advice:

Always declare checked exceptions individually, and document precisely the condition under which each one is thrown using the Javadoc @throws tag. .... While the language does not require programmers to declare unchecked exceptions that a method is capable of throwing, it is wise to document them as carefully as the checked Exceptions.


Unfortunately, the expert's advice didn't work in my co-worker's case. Should I say in most cases? He is with the sad majority of developers, that don't ready javadocs - not even on public API methods. Maybe I should have listened to people telling me this:

I kind of disagree with your example; documenting everything in every tiny detail may be a requirement for widely used public APIs (like the JDK), but IMHO a more relaxed approach is useful for the rest of us. Like "configuration by exception" is considered a good idea, there should also be "documentation by exception". That is, don't document every tiny detail but instead follow some higher level conventions. Many people do that intuitively, but unfortunately forget to document those conventions.


Like Matthias, my co-worker argued, that he thinks conventions should define what happens if e.g. you pass null to a method or which Exceptions are being thrown from an API method. I do agree, conventions are a great tool to define this kind of behavior. The problem with conventions are: How do you get the whole team to agree on certain conventions and more important - how do you manage those convetions?

Getting a team of strongly opinionated individuals to even agree on minor details, e.g. how to name interfaces, is almost impossible. Believe me, I have been there! After more than a year, we still can't agree on wether to use Eclipse's notation of IService or my preference - simply Service. I cannot imagine how hard it will be to agree on really important topics like passing null to methods and wether to throw IllegalArgumentException or NullPointerException in that case.

The second issue with conventions is how to manage them. Who is responsible to maintain those agreements? Do you put those conventions on a wiki page, which nobody updates and nobody reads anyways? I argue, that for us developers code and eventually the IDE is where we live, thus I think that's the place those conventions should live as well. Code is the common single point of truth for us and hence javadocs are in my opinion the best way to document any code related conventions.

I guess you can see where this is going. It's a trade-off, as always in software development. However, it's a trade-off with a catch. I think it's simply not enough to "just have conventions", they need to be documented and managed in the code and my weapon of choice for doing that is javadocs.

6 comments:

Dr.Mz said...

Hi,

If the main purpose of the code sample you describe is just to do its best to complete as many jobs as possible despite particular job failure, then it should handle unchecked exception in any case, since even if you throw a checked one, others deep down in stack trace might not. So IMHO throwing checked or unchecked exception, documenting exception or not etc- It all does not make big difference - the caller should just handle as many exception situations as possible (checked exceptions, runtime exceptions, errors)

BR.
Stas.

david said...

It all does not make big difference - the caller should just handle as many exception situations as possible (checked exceptions, runtime exceptions, errors)

Oh I think it does make a difference. If you declare a checked Exception on an API method, the caller is forced to handle it - the compiler will help you do the right thing. If you have an unchecked exception, as you say "the caller should just handle as many exception situations as possible", but he is not forced to.

Dr.Mz said...

That's true. However my point is that even if you are using a checked exception for your particular case you still can have an unchecked one being raised by your job. Consdering this an author of the code sample you describe should care about unchecked exceptions anyway.

david said...

However my point is that even if you are using a checked exception for your particular case you still can have an unchecked one being raised by your job.

I agree, but I would expect an API to declare, preferably in the javadoc or method signature, the Exceptions raised, when calling the method. You don't get any unexpected Exception when using the Collections API, you get the Exceptions declared in the javadocs.

BTW that's what I was writing about in Does Your API Docs Leave Users in the Dark?

Dr.Mz said...

Of course you should document as much as possible. It's not a question.
I guess we're just having a bit different contexts - your example made me think of some sort of generic enough task execution engine that knows nothing about tasks it executes and thus should assume the worse to do its best in doing its own job :).
And BTW you can easily get an "unexpected exception" when working with collections API if for instance objects you store in the collection throws something in their equals/hashCode methods :)

david said...

And BTW you can easily get an "unexpected exception" when working with collections API if for instance objects you store in the collection throws something in their equals/hashCode methods :)

A little bit far fetched, but point taken :-)


com_channels

  • mail(dlinsin@gmail.com)
  • jabber(dlinsin@gmail.com)
  • skype(dlinsin)

recent_postings

loading...