Sunday, December 5, 2010

Problems with Checked Exception in Java

Recap: Exception Hierarchy In Java

In Java, we have three types of Throwables :
        1. Error and it’s subclasses
        2. Runtime Exception and it’s subclasses
        3. And the rest (Non-Runtime Exceptions)

Exceptions those lie in the third category are called Checked Exceptions. If a method throws a checked exception, the compiler makes sure that the API user handles it either by using try-catch block or by propagating it to the higher layer by adding a throws clause to the method definition. The throwables belonging to the first and second category are unchecked in nature. Compiler does not force the API user to handle them.

The Thumb Rule


As an API author (Somewhere I read that every method is an API, if it is a public method then it is exposed to the world, if it is a private or package-private method it is an API for internal usage. I liked the concept), you should use a checked exception only when you believe that the API user can recover from the exceptional situation. If it is not recoverable, Runtime Exception (unchecked throwable) should be used.
As a rule, errors are generally reserved for JVM related issues (e.g OutOfMemoryError, StackOverflowError etc). So, if a custom exception needs to be written which you believe, should always be recoverable then extend it from the Exception. Otherwise for any custom unchecked exception derive it from Runtime Exception. Hence,
  •     Expected + Recoverable -> Checked Exception
  •     Unexpected + Not Recoverable -> Runtime Exception
Problems with Checked Exception

1.  As mentioned earlier that a method should throw Checked Exception, if the API author believes that the API user can recover from the exceptional situation. But, in real life, whether an exception is recoverable or not depends on the situation - for the same piece of code one exception may be recoverable in one context and may not be recoverable in some other context. Let’s take up one example. I work with telecom subscriber provisioning system. There lies a method which validates the cell phone numbers of subscribers.

  • If an operator tries to create a new subscriber through the UI by providing an invalid number, the Number Validation Method should throw back a checked exception, because it is recoverable. The operator would be asked to re-enter a valid phone number.
  • The operator is trying to search for the number of a particular subscriber. It is being read from the DB and then validated using the same Number Validation Method. If the number is found to be invalid, the method should throw an unchecked exception, because it is NOT recoverable this time. The subscriber data has got corrupted in the DB.
By throwing a checked exception, the API author is forcing the API user to handle it. If there is no way to “actually” handle the exception (i.e. recover from the exceptional situation), what will the user do then? In such a situation, most of us do one of the following:
  • Swallow the exception by providing an empty catch block (This is nothing but a bug)
  • Provide a catch block just to log the occurrence of the exception. (This is also the same) 
  • Catch the exception and re-throw it.
This is true in 90% of the cases. Of course, there is a so called better solution - catch the exception, convert it to a more meaningful checked exception and pass the ball to higher level. But, this may lead to another problem as indicated in point number 3 below. The ideal solution, I believe, is to catch the checked exception and convert it to an unchecked exception. Although, in Java, the concept of try-catch was introduced to handle the exceptional conditions, but it’s very rare to find a catch block where the exception is really handled.

The bottom line is:
  • Things may go beyond API authors “belief” and quickly become messy.
  • Most of the time we use Java’s (checked) exception handling machinery just to log the exception (and then raise a bug and fix it).
2.  In my application, I wrote an API which throws one checked exception E1 and published the API to the world. Now, because of some new features, the implementation of the method has to be changed and it has to throw two new exceptions, say E2 and E3. If E2 and E3 are checked exceptions, all the client code which are using the API till date, will break. The way outs are:   
  • Catch E2 and E3, then convert them to E1. I believe that defeats the use of exception.
  • Publish new version of the API.
3.  try, catch is not the only way to handle a checked exception. If the exception can not be immediately handled, it may be propagated to the higher layer by declaring throws clause. In the higher layer of the stack, the exception can be handled in a better way. This may also be problemetic in cases. Say, for a large, layered application one new API is being developed. It internally invokes three other APIs. Each of those three methods in turn throws three checked exceptions. If the new API is not in a position to handle any of those exceptions immediately (inside the method code), how many exceptions would be thrown back? NINE. Will not be it difficult for the client to use the API?

4.  Another use case of checked exception is worth mentioning. Say, for an UI application, all the methods in all the classes throw the same user defined checked exception called GuiBaseException. Different instances of same exception bubble up from different layers of the code in different exceptional situations and all of them gets handled by the same exception handler at the top most layer. With this approach, everybody is happy - the API author is happy because he believes that “recoverable” exceptions should always be checked, the API user is happy because he is handling them without any pain and effort (also without making the code dirty by introducing try and catch here and there). Wonderful solution, but it completely defeats the very idea of exception handling!

Then What?

Though Checked Exception conveys an warning message to the user “Heey! you need to pay attention”, but in most of the cases, that warning is ignored.
With the usage of ONLY Unchecked Exception (i.e. by avoiding checked exceptions), problems 1, 2, 3 can really be addressed. No body is going to force the API user to handle the exception. Every thing would be properly documented. The API user would decide whether to handle it or not depending on the context.

Ok, this one liner may not be a full proof solution. In fact, I am not trying to give a solution also. The aim of this post is just to capture the problems with checked exceptions. Yes, accept it or not; Checked Exceptions are problematic. Java did an experiment by introducing this concept with a lot of great expectations, but as per my understanding, over time it has been proved to be a failure.
C# does not have checked exceptions and the same is true for other JVM based languages like Groovy and Scala.

Dear Reader, what do you feel about it? Which camp are you in - Checked or Unchecked? :-)

Further Reading:

6 comments:

  1. I have some comments on the above points mentioned, just to put my own perceptions and present my perspectives on the mentioned points

    1. It is true that whether an exception is recoverable or not depends on the situation/context when/where the exception had occurred.
    This is the same reason, I believe, all RuntimeExceptions are unchecked. Because, technically speking, all java methods are capable of throwing different types of RuntimeException, isn't it? Because compiler does not know beforehand that a method cannot throw NullPointerException during runtime. So if java language is designed in that way think of the horror of putting catch blocks everywhere for this type of trivial exceptions.

    Instead they had come up with different idea. They clearly divided the demarcation betwenn erswhile undivided exception family. Below is the excerpt from JLS:

    "The runtime exception classes (RuntimeException and its subclasses) are exempted from compile-time checking because, in the judgment of the designers of the Java programming language, having to declare such exceptions would not aid significantly in establishing the correctness of programs. Many of the operations and constructs of the Java programming language can result in runtime exceptions. The information available to a compiler, and the level of analysis the compiler performs, are usually not sufficient to establish that such run-time exceptions cannot occur, even though this may be obvious to the programmer. Requiring such exception classes to be declared would simply be an irritation to programmers."

    Along with that they had introducued innumerable no. of RuntimeExceptions which can be readily used in different trivial situations.

    If you notice, nowhere it is mentioned the samantics/usage guidelines whe/where to use checked/unchecked exceptions. This is a trend provided by early proponents of the language.

    As an API author, I can only visualize what "extra" exceptional situations one might face if they use my API.(other than trivial NullPointerException :)). Like java.io.* packages introduce a generic IOException and its specialized subtypes which may come up when one uses some class/methods from that package. My perspective of an API is that it is a self-contained piece. Its a mere one building block rather than a building itself. So it exposes the 'handle with care' tag. I mean, which are the extra burden API user has to carry to use this. Its upto API author's perspective which he/she thinks needs to be thrown.

    But an application is made of thousands of such building blocks and typically composed of different layers. A lowest layer can throw FileNotFoundException every now and then but a comparatively higher layer , which typically has some broader view, may decide whether its a really exceptional scenario or not.
    For example if you have ever seen Windoes event viewer, you will find hell lot of error/warning events that have been continuosuly happening in system. But for only few thing the OS cribs and pops Send/Don't send box.

    Depending on this they can throw it as it is, can wrap it in more application specific checked exception etc.

    For example,
    a) The java.util.Enumeration.nextElement() method throws NoSuchElementException (FYI its a RunTimeException) if no elements found. It is , you can say, an exception thrown from lowest layer. But application developer/API user can put hasNextElementCheck() method before calling nextElement() call and can safely use. Similar analogy can be used for checked exceptions

    ReplyDelete
  2. Java 7 introduces multi catch throw which can appease us as we generally handles all excetion in same way.
    catch it, log it, throw it isnt it :)

    ReplyDelete
  3. Thinking of checked exceptions as a problem indicates a failure to recognize what software development involves. Getting the software to produce proper results when given proper inputs is naturally the most important aspect of software development. But the next most important aspect of writing software is detecting and handling problems.

    Thinking that checked exceptions are a problem (and that handling them isn't possible or important), indicates that the developer has failed to realize what their second-most-important responsibility is.

    ReplyDelete
  4. An edge case point, but Throwable and its sub classes are all checked except Error and RuntimeException and their subclasses.

    i.e. you can create your own branch of Throwable and it will be checked. That doesn't make it a good idea. ;)

    ReplyDelete
  5. > With the usage of ONLY Unchecked Exception (i.e. by avoiding checked exceptions), problems 1, 2, 3 can really be addressed.

    All it really does is ignore the problem. Its a cross your fingers and hope the documentation is up to date and being read and actioned by all developers everytime there is a change.

    There are APIs in the core java which throw undocumented unchecked exceptions. The only way to know what they are is to read all the code to find them.

    IMHO, a catch block should handle the exception. Otherwise, the catch block is pointless and shouldn't be there.

    ReplyDelete
  6. I agree that some time boiler plate code for checked exception make code unreadable but there are many techniques to get around this problem one of them is wrapping Checked Exception into uncheckedException, spring has used it quite well and converted many JDBC related exception into DataAccessException.Also Java7 new feature multiple exception in one cache block and Automatic resource management provide some relief.

    ReplyDelete