Exception constructs in modern languages have replaced the way to map an error condition by a return value (like for instance in C). If used properly analyzation of error conditions and their handling can be performed very well. Never the less in Java, the so called checked exceptions are annoying since long (as a side note: C# seemed to have learned from this early language-design mistake because it supports unchecked exceptions only). This article discusses further why checked exceptions should be avoided.
This topic was already discussed by clever Bruce Eckel, who is also thinking that checked exceptions aren’t such a good idea. To his reasoning one thing I would like to add is the “blurry assumption of api-interface” problem.
Anticipation of incoming dependencies not possible
Officially Sun mentions that checked exceptions should be used in case of “expected” exceptions, where clients still could react. In contrast unchecked exception should be used if programming erros occur, where a reaction is hardly possible (e.g. NullPointerException, AssertionError).
In case of checked exception client code can decide whether to react to it directly (try/catch) or to delegate and pass it in the throws clause. In practice many checked exceptions aren’t interesting to client code, therefore you start to pass it to the throws clause. After a while spreading exceptions between different class-collaborations they are getting piled up and code-distraction is king and developers are constantly typing irrelevant code.
I’ve often seen code where developers got fed up with this pass-through of exceptions, workarounded this with a bad exception handling coding style. So, in theory checked exceptions should increase code quality but in practice I perceived the opposite. This is bad, because a programming language design should help you to write good code and not constrain your work. Following workaround code snippets are quite common:
//no handling code
//swallowed away nirvana exception
Above is evil: Though exception should somehow be reported in lower area of method call stack, this try/catch just makes any error handling impossible. Such “nirvana” exceptions can make your life really hard when locating defects.
throw new RuntimeException(“Error I don’t know what to do with. Got fed up with
throws clause in all my method declarations!”);
Problem is that above newly thrown RuntimeException is too general and analyzation of certain error-conditions is hard. Often the causing checked exception isn’t even passed to the RuntimeException constructor so finding the root cause of a failure is also difficult.
To summarize: If client code cannot handle the exception, in practice checked exceptions aren’t passed to throws clause of method declaration. Indeed you can get really crazy if you need to pass the exception the whole method call-stack. Especially when doing bigger refactorings such millions of checked exceptions in the throws declarations are extremely annoying. Looking at this shortcoming developers often go for an improper exception handling. The difficulty of api-designers is that they cannot anticipate the exception-interpretation of incoming dependencies and thus the use of a checked exception can lead to bad exception handling code. They just don’t know, if a handling of an exception makes sense or not, see following examples:
Example checked IOException
Trigger: IOException from java.io api gets thrown because a file under given pathname cannot be found.
Handling appropriate: My client-code represents a file system manager, where I am searching for a file. The information “File not found” is directly relevant and file system manager could proceed to look in other directories.
Handling not appropriate: I got a general app, where a property file should be loaded. Then the app should crash early/instantly, most likely I set a wrong path (Programming error).
Example checked RemoteException
Trigger: RemoteException gets thrown, because network connection for RMI communication is broken.
Handling appropriate: My client-code is a network monitoring tool and such information should be logged down for server downtime analyzation. Thus exception should be directly handled.
Handling not appropriate: I got two application components which are communicating with RMI. The defect is a misconfiguration of the firewall. Application itself cannot react on this, it is a plain network setup defect.
Now Sun’s exception convention gets into problems: They told that Programming-Errors should always be mapped to unchecked exceptions… As shown above this does not work out, in some contexts the root cause of IOException is a Programming error (property-file loading) in some not (file-manager).
Way out of checked exceptions
Most likely Java standard won’t change this exception design-flaw, especially for backward compatibility reasons. But there is still a solution: When you are forced to handle checked exceptions constantly you can wrap them in custom unchecked exceptions (-> extending an own custom exception hierachy from RuntimeException). This way other client code does not need to bother to look at non-interesting exception. The implication of mentioned points could also be that your api-design should only offer unchecked exceptions in method declarations.
Following this clients are not distracted by always doing this try/catch duet and code further more gets much better readable. Of course you should not just shove all checked exceptions directly into a RuntimeException (one of the workaround I explained above), you should be more concrete and build up a deeper exception type-hierachy to make further handling easier. Besides you should chain checked exception and pass it to the unchecked exception’s constructor to later find out root causes better.
Of course at one point such unchecked exceptions need to be handled at the outmost layer latest to make a proper report possible (e.g notifying monitoring/logging, sending back a user-friendly error HTML-message). You really don’t want to spill the whole stack-trace to a HTML or SOAP response or make your application to completely always shutdown.
Java introduced checked exceptions, which seemed to be a good idea in the first place to enforce clients to “have to know” about certain error conditions. But in practice developers do not pass “uninteresting” exceptions in throws clause, because code gets crowded and diffult to understand. They merely tend to workaround with inappropraite exception handling. Further more the view on exceptions, wheter they are worth the be catched or not, is context based and cannot be anticipated. To avoid this problem api-designers or client code generally should go for unchecked exception and a custom unchecked exception type-hierachy.