This post originated from an RSS feed registered with Java Buzz
by Rajiv Shivane.
Original Post: Why do catch clauses need to be ordered?
Feed Title: 0xCAFEFEED
Feed URL: http://feeds.feedburner.com/cafefeed
Feed Description: Thoughts on JavaTM/J2EETM and related technologies
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
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.
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:
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:
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.
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?