Checked Exceptions Reality Check

Mark Hooijkaas, $Revision: 1.3 $, $Date: 2004/05/31 23:34:36 $

The beauty of exceptions

In the C family of programming languages (C, C++, Java, C#), exceptions were first introduced with C++. In C, and other programming languages without exceptions, dealing with errors or other “exceptional circumstances” was very cumbersome and error-prone:

Without exceptions writing a simple statement like

	config_file = fopen(filename, “r”);
becomes something like
	config_file = fopen(filename, “r”);
	if (config_file==NULL) {
		/* clean up */
		set_error(PROBLEM_READING_CONFIG_FILE);
		return;
	}

The use of exceptions solves all of these problems:

Checked and unchecked exceptions

In the Java programming language something new was added to the exception mechanism: the checked exception. A checked exception is any exception that inherits from Exception but not from RuntimeException. If there is a possibility that a java method can throw a certain kind of checked exception a programmer must explicitly mention this in the interface of this method (the “throws clause”). The compiler checks if a programmer has done this correctly, and reports an error if in the implementation of a method a certain type of exception can occur that is not explicitly handled by the programmer by either catching this error (or any parent class) or mentioning it in the throws clause (or any parent class).

A slightly different view on checked exceptions is that by mentioning a specific exception type in the throws clause of a method, forces any user of that method to handle that error by either catching it, or by mentioning it in it’s own throws clause.

Checked exceptions in practice

On first sight, I (and any other programmer I know) really liked this idea of the compiler helping a programmer in ensuring that all possible errors has been handled or acknowledged. Forcing a programmer to handling or acknowledging each possible type of error, should help make code more robust.

The idea of checked exceptions still seemed to be a great idea on second sight when compiling small and medium sized programs. It often is a pain to get all the throws clauses right. Also, when some implementation deep down changes one often has to change the throw clause of many methods to propagate a new exception up call trees. However the idea is that all this work to get a program to compile correctly would benefit the robustness of the program.

However, when one looks at the practice of large programs, with often many programmers working on the same program, certain problems in the use of checked exceptions appear:

Especially the last issue is troublesome when using agile methods, where code should be designed to be flexible so it easily can be changed due to changing demands or otherwise refactored.

Exception Wrapping

Most projects have adopted some kind of Exception Wrapping mechanism. Basically, in a method, one catches a certain type of exception, and throw a different kind of exception, while trying to preserve as much information as possible. In recent Java versions it is possible to include the original exception when creating a new exception, thus the term exception wrapping.

The following code fragment is an example of exception wrapping

	try {
		readConfigFile(filename);
	}
	catch (IOException excep) {
		trhow new ConfigFileException(excep);
	}	
Exception wrapping is indepedent of the issue of Checked Exceptions. Even for unchecked exceptions (e.g. as used in C++, C# or Python), it can be useful to transform low-level exceptions into higher level more specific exception types.

In Java one must use some kind of exception wrapping to mitigate the problems of checked exceptions as mentioned in the previous section:

Without exception wrapping, it becomes impossible to realize large projects. Unfortunately, often the sole purpose of the exception wrapping seems to be to satisfy the compiler complaining about checked exceptions. In these cases there often is one or a small number of base exceptions that alle detailed exception classes derive from. For example, in a project there might be a ProductXyzException class, or sometimes each there are PackageAbcExceptions and PackageKlmExceptions classes for each major package. All methods can then just claim to throw such an exception (and al it's derived exception classes), and new exception classes can then be added without a need to change the signature. It is needless to say that this is not a good practice, because all information about what kind of exceptions may be thrown is lost. Any method that has a "throws ProductXyzException" basically claims "I can throw many different kind of exceptions, I really dont have any idea

Why I still don't like checked exceptions

Some people believe that using a well designed Exception hierarchy, can solve the problems with checked exceptions. I agree that in theory a designer should carefully design an API with logical / functional exception specifications. However, I would like that exception hierarchy to use unchecked exceptions, since a well designed exception hierarchy is not only possible with checked exceptions. The fundamental problem with checked exceptions is that
  1. A checked exception forces the calling method to conciously handle that exception, by either catching it, or acknowledging it in the throws clause.
  2. In 99% of the methods a method cannot sensibly handle an exception other than passing it through to it's caller (either wrapped or not).
However, in reality