Jun 14 2007

Why do catch clauses need to be ordered?

Tags: Rajiv @ 8:30 am UTC

Looking at question #15 on JDJs Secrets Of The Masters: Core Java Job Interview Questions (Secrets of the masters???!! Whhoaaah!!), I was reminded of the question Vinod once asked me: “Why do catch clauses have to be ordered?”

It is generally known that, in Java, the order of the catch clauses is important. The more specific exceptions have to be handled first followed by the less specific exceptions. So, the following snippet of code causes a compilation error, as FileNotFoundException is more specific than IOException (FileNotFoundException extends IOException).

 try{
  //Some File I/O operations here
 }catch(IOException e){
  //handle the I/O error
 }catch(FileNotFoundException fnfe){
  //handle the case when the file is not found
 }

To fix it, you need to change the order in which the exceptions are handled by moving the more specific exception (FileNotFoundException) before the less specific exception (IOException), like so:

 try{
  //Some File I/O operations here
 }catch(FileNotFoundException fnfe){
  //handle the case when the file is not found
 }catch(IOException e){
  //handle the I/O error
 }

This change is so straight forward that, any smart IDE can do it for you

Screenshot of IntelliJ IDEA's suggestion to move catch clauses around

So Vinod’s question really was: Why didn’t the designers of the Java language make the compiler smart enough to sort the catch clauses automatically (instead of pushing the burden on to the IDEs/developers)?. To quote him verbatim (including the typos) from my messenger archive: “.. i mean you are asking the programmer to think like compiler than compiler think like a programmer … from a programmer perspective… i want to catch FNFE if the exception is of that type other wise cathc IO”. Interesting point .. I never thought of it before.

Spoiler: I don’t know the answer, what follows are my thoughts or possibly my stream of consciousness, like my article on Why is finalize method protected?.

Having found no clues in The Java language specification I thought the answer probably lies in the history of Java. A Brief History of the Green Project is a good place to start. This page gives history of Java (it was originally called Oak) and has a copy of the version 0.2 of the Oak language specification [PDF]. The spec gives an interesting perspective on how the Java language evolved.
Having found no clues in The Java language specification I thought the answer probably lies in the history of Java. A Brief History of the Green Project is a good place to start. This page gives history of Java (it was originally called Oak) and has a copy of the version 0.2 of the Oak language specification [PDF]. The spec gives an interesting perspective on how the Java language evolved.

Side tracking: Interesting tidbits from the Oak specification

  • Throwable was earlier called GenericException
  • Asynchronous Exceptions: one thread can throw an exception (using Thread’s postException() instance method) to another thread
  • The protect/unprotect keywords
  • You could use //* javadoc here notation to write java docs apart from /** javadoc here
  • print and println were operators. System.out was possibly a refactoring
  • Interfaces declared constants using const instead of public static final. Like const int aConstant = 42;
  • Supported assertions, preconditions and postconditions
  • Has no details on threads, serialization nor does it have a BNF

Side tracking again: Catching multiple exceptions in one catch clause

Many a times people ask me: “Why can’t I catch multiple exceptions in one catch clause, I generally end up pasting same error recovery code in all the catch clauses. Why isn’t a catch clause like a method signature, where I can have a comma separated list of all the exceptions to be handled?” What they want is some thing like this:

 try{
  //Some File I/O operations here
 }catch(FileNotFoundException fnfe, IOException e){
  //common error handling
 }

The question itself seems to have the answer. If all the exceptions were listed like method parameters, the above snippet of code would mean “Do the common error handling if BOTH FileNotFoundException and IOException are raised” instead of “Do the common error handling if EITHER FileNotFoundException or IOException is raised”. The solution probably would be to use the OR operator “||” instead of commas? Some thing like:

 try{
  //Some File I/O operations here
 }catch(FileNotFoundException||IOException||MyNewException e){
  //common error handling
 }

Incidentally, the Oak specification also compares catch clauses to method definitions. From section 9.4:

A catch clause is like a method definition with exactly one parameter and no return type. When an exception occurs, the runtime system searches the nested try/catch clauses. *snip*

If you have two overloaded methods called handle, of which one takes FileNotFoundException as a parameter and the other takes IOException as a parameter, java always knows which method to call. It automatically calls the most specific method based on the runtime type of the object.

 private void handle(FileNotFoundException fnfe){
 }

 private void handle(IOException e){
 }

Now, as suggested by the spec, each catch clause can be treated as an overloaded method which takes a subclass of Throwable as a method parameter and no return type. Now extending the method overloading analogy shouldn’t java be able to detect which catch clause to invoke? Unfortunately, the complete paragraph from section 9.4 reads:

A catch clause is like a method definition with exactly one parameter and no return type. When an exception occurs, the runtime system searches the nested try/catch clauses. The first one with a parameter type that is the same class or a superclass of the thrown object has its catch clause executed. After the catch clause executes, execution resumes after the try/catch statement. It is not possible for an exception handler to resume execution at the point that the exception occurred.

The question now is, instead of continuing the method definition analogy and supporting overloading semantics to the catch clauses, why does the spec say the first catch clause will be chosen?

One possible reason could be for ease of compiler development. This seems to be an unlikely motivation.

Other possible reason could be for code clarity. What if the java developers start to expect that all the exception handlers that match are invoked? The problem exists with or without auto-sorting of catch clauses. A switch like construct would have been more appropriate then:

 try{
  //Some File I/O operations here
 }catch(Throwable t){
  switchOnClass(t){ //using a hypothetical keyword switchOnClass
   case FileNotFoundException:
    //handle file not found error
    break;
   case FileNotFoundException:
   case MyNewException:
    //some processing for both FileNotFoundException and MyNewException
    break;
  }
 }

Or the other possible reason is because Java’s exception handling was based on C++’s (as mentioned in the foot notes of the Oak spec page 26). C++ allows multiple inheritance. So my class MusicStreamingException could extend both MusicPlayerException and IOException. Now assume the compiler see’s this piece of code:

 try{
  if(someCheckHere())
   throw new MusicStreamingException();
 }catch(IOException e){

 }catch(MusicPlayerException e){

 }

Both the catch clauses match equally and the compiler has no way of determining which one to invoke. Hence the best policy would be to choose the first catch clause. However, this would never happen in Java as it does not allow multiple inheritance, else the same problem would exist in overloaded methods. Is it possible that this requirement in the spec is only a legacy from C++? And can it be done away with without impacting the existing code?

Share:
  • email
  • del.icio.us
  • DZone
  • Technorati
  • Reddit
  • Ma.gnolia
  • Google Bookmarks
  • YahooMyWeb
  • SphereIt
  • StumbleUpon
  • Digg
  • Mixx
  • TwitThis
  • Furl
  • Simpy

No trackbacks

9 comments

  1. Rupesh Kumar


    Wow.. Thats really interesting. I had never thought about this. We are sooo used to follow the specification rather than question it :-)
    This made me look into our CFML compiler and the way it invokes the catch clause. Since CFML exceptions are ultilately java exceptions and the compiler is also written in java, we catch Throwable and do the exact match for all catch types. So there is no order needed for CFML.
    I really wonder why Java was not done that way.

    My guess is that perhaps these guys first decided to have mutiple inheritance in java and write exception handling based on that. They later backed multiple inheritance off but left this as it was :-D

  2. Rupesh Kumar


    btw dude, “Secret of The Masters” was awesome ;-) LOL !! Looks like JDJ is not getting any articles to publish..

  3. Scott


    I think the answer may be simpler than that: like most of the worst parts of the original Java spec (let’s all cheer for breaking after each switch case), this behavior is exactly the same as C++.

  4. Sachin


    Excellent read!

    My thoughts on this topic – but before that I just wanted to mention that I believe overloaded method calls are resolved at compilation time itself and are statically determined so there is no way the ‘right’ overloaded method call can be made cheaply at runtime. It is method overriding (polymorphic behaviour) that is dynamically determined.

    I think it is possible that runtime performance of exception handling is a big reason why the Java runtime expects exception handlers to be organized the way they are (most specialized to most generalized). I guess the exception handling code can then just work its way down the list and the first handler that returns true for Class.isAssignableFrom would work (I don’t know what the actually byte code generated is so I may be wrong). If it was required to determine the best handler out of them all at runtime, all handlers have to be visited and the best one recovered at runtime making it much slower.

    However, despite this the question is still valid because the compiler can still be responsible for re-ordering catch clauses as expected by the runtime and not pose the restriction on the programmer. Here, I believe the reasoning could very well be usability. I would argue that providing this ‘flexibility’ is less usable because, although there is more flexibility while programming, the code becomes less maintainable. It is no longer possible to read the exception handling code without manually performing this operation every time you read such code. Making the programmer do it once is an overhead that saves time many times over.

    If Java were designed with a philosophy of “more power to the programmer” then I would expect this would be supported (and we would then have had someone suggest as a good coding guideline that everyone organize their catch clauses this way for readability) however Java does take the more restrictive approach to programmer flexibility and this seems to be in keeping with that.


  5. rajiv


    Hey Sachin!

    Sachin: I believe overloaded method calls are resolved at compilation time itself

    Yes. Thanks for correcting!

    Sachin: the question is still valid because the compiler can still be responsible for re-ordering catch clauses

    Yes, that was what I was hoping the compiler would do.

  6. Doug Pardee


    I think that Sachin is partway there, but got derailed.

    Sometimes to understand the why’s of Java, you need to remember that Java is 100% dynamically bound. The hierarchy of exceptions at runtime will not necessarily be the same as the hierarchy that existed at compile time.

    The compiler cannot determine (with 100% accuracy) which exceptions will be specializations of which other exceptions when the code is actually executed. Reordering the clauses at compile time would work most of the time, but could result in erroneous results. This is something that is better left to the IDE, where the programmer can choose to do it or not and can intervene if the resulting order is inappropriate.


  7. rajiv


    Doug:

    The compiler cannot determine (with 100% accuracy) which exceptions will be specializations of which other exceptions when the code is actually executed.

    The same limitation applies when compiler is trying to resolve which overloaded method is being invoked. The most specific overloaded method is chosen based on the inheritance hierarchy at compile time. Yes, this hierarchy could be broken at runtime during the invocation of the overloaded method, just like for exceptions.

    If the compromise is ok for overloaded methods it should be ok for catch clauses.

  8. Doug


    No, they (exceptions and overloading) aren’t comparable. And yet they are comparable.

    They aren’t comparable because overloading results in a runtime reference to a method with a specific signature. Exceptions, on the other hand, are not specific—a single “catch” clause can catch many subtypes of exceptions.

    They are comparable because with both exceptions and overloading, the Java specifications leave it to the programmer to deal with the potential mismatch between compile-time and run-time. The proposal would take that control out of the hands of the programmer in the case of exceptions.


  9. rajiv


    Doug:
    Isn’t that exactly what Sachin was saying? That overloaded methods are resolved at compile time and catch clauses are resolved at runtime?

    What I am expecting is that compiler could sort the catch clauses and put then in the class file in sorted fashion based on the class hierarchy at compile time. However, this need not affect the runtime resolution of catch clauses. That is, the catch clause executed at runtime is chosen based on the runtime type of the exception being raised.

Leave a Reply

Subscribe to comments on this post

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>