The use of checked exceptions in Java is still widely debated. This post contains thoughts on their use by Java experts such as James Gosling, Joshua Bloch (Effective Java) and Bruce Eckel (Thinking in Java), before countering some of the arguments against their use, such as how I don’t believe they break encapsulation, and that their use shouldn’t be limited to truly exceptional conditions. It finishes by looking at when alternatives to checked exceptions should be used. The overall slant of the article is that there are many reasons why Exceptions, including checked Exceptions, should still be a part of your Java arsenal.

OVERVIEW

An Exception is an event that occurs during the normal course of execution in a program and that alters the normal flow of control. There are two main types of exceptions in Java, checked and unchecked.

The use of exceptions in programming languages to signal special conditions that change the normal flow of execution is nothing new and common in many programming languages. Java however was the first (and is still the only mainstream) language to use checked exceptions. They are, for example, not used in C, C++ or .Net. Checked exceptions are characterized by a compiler enforced need to be dealt with (“catch”), as well as being part of a method’s signature (“throws”).

Unchecked exceptions

Unchecked exceptions represent exceptional conditions that the application usually cannot anticipate or recover from and so methods are not obliged to establish a policy to handle them. There are two main types: Runtime Exceptions and Errors:

Runtime Exceptions

exceptional conditions internal to the application (e.g. programming bugs, such as logic errors or improper use of an API)

Errors

used by the JVM – you should never really need to throw these in your own code

e.g. IOError, AssertionError

Represent exceptional conditions external to the application (e.g. hardware or system malfunction)

Checked exceptions

Checked exception are subclasses of Exception (excluding the above mentioned Runtime Exceptions) and represent exceptional conditions that a well-written application should anticipate and recover from. A method is obliged to establish a policy for all checked exceptions thrown by its implementation, either by passing further up the call stack (i.e. propagate using throws), or by handling using try/catch blocks.

Exception Hierarchy

Benefits of using exceptions

Centralize error handling logic. Instead of having to deal with errors everywhere in the code they can happen, you can throw exceptions and have them dealt with elsewhere, including grouping similar error types together

CHECKED EXCEPTIONS: THE GREAT DEBATE

Ask 10 people about the use of checked exceptions and you are likely to get 10 different answers. Below, I try to summarize the views of some of the leading Java experts before concluding with my own opinion…

The creator of Java himself still thinks that Checked Exceptions are a good idea because although you can ignore them, you have to willfully do it. You can’t accidentally say, “I don’t care.” You have to explicitly say, “I don’t care.” (1)

Joshua Bloch
Joshua Bloch is author of Effective Java, co-author of Java Concurrency In Practice and creator of the Java Collections framework. His Effective Java contains half a dozen items on exceptions, but the key ones are:

Only use Exceptions for exceptional conditions (never use for ordinary control flow)

Use checked exceptions for recoverable conditions and runtime exceptions for programming errors.

Avoid unnecessary use of checked exceptions

Bruce Eckel
The author of “Thinking in Java” considers Checked Exceptions to be a mistake; a failed experiment (2) and this is not a particularly unusual opinion, with many people feeling that unchecked exceptions should always be used in preference to checked exceptions. For example, Spring, EJB3, JDO and Hibernate have all moved towards reducing or eliminating the use of checked exceptions.

Joel Spolsky
The author of Joel on Software goes even further and believes all Exceptions to be no better (and indeed significantly worse) than “goto’s” (3). Although I should say I strongly disagree with this!

That is a wide variety of opinions, and they can’t all be right. Why is there so much debate over their usage?

WHY I THINK CHECKED EXCEPTIONS ARE OK!

Break Encapsulation?

One of the main arguments against using checked exceptions is that they break encapsulation by revealing implementation details, as well as forcing a tighter coupling between the method and its callers.

While this can be an issue, I believe that the solution is to never let implementation-specific checked exceptions escalate to the higher layers. For example, never let a service later exception propagate to the web tier. Additionally, to avoid excessive API pollution, exceptions inheritance (e.g. throwing a superclass exception, rather than several exception subclasses) can be used to reduce the number of exceptions. So in reality, an exception shouldn’t expose the inner workings of a method any more than a return type does. And in many ways, a thrown exception is an alternative return value.

Only for ‘exceptional conditions’?

The other issue surrounding the use of checked exceptions is uncertainty around what constitutes an ‘exceptional’ condition. Most people would agree that not being able to connect to a database is an exceptional event and that a program cannot realistically be expected to continue until that is fixed, so it is correct to deal with that situation via an exception (and specifically, a unchecked exception). But what about situations where an event occurs that is not part of a ‘normal’ flow, but that you do expect to happen, albeit it rarely. For example, imagine a method that is tasked with retrieving a user account. The method may not be able to complete for a number of reasons such as the account being locked, having been deleted or the current user may not have permission to access it.

These outcomes aren’t exactly exceptional conditions in that they are all bound to happen at some point during the normal use of the software, so is it still correct to use exceptions to deal with them? I believe yes and that this is exactly what checked exceptions are for. These situations fall under what can be called contingencies. This approach to using checked exceptions is covered well in this Effective Exceptions article by Barry Ruzek. He differentiates faults and contingencies, defining the latter as “an expected condition demanding an alternative response from a method that can be expressed in terms of the method’s intended purpose” and advocates using checked exceptions to enable the caller of the method to provide strategy for coping with these expected outcomes.

WHEN NOT TO USE CHECKED EXCEPTIONS

So, while I don’t think checked exceptions break encapsulation, are fine to use for contingencies and in general are a useful tool, that it not to say they should be used all the time. There is a considerable overhead in using them, and so the guidelines on use of checked exceptions above from Joshua Bloch should be observed (including never use for normal program flow, use only for recoverable conditions, and avoid unnecessary use).

One way to avoid their unnecessary use is to use a state testing method before calling the method that could potentially throw the exception. That way, if the preconditions is broken, it is a violation of the API and therefore it is perfectly OK to respond with an unchecked exceptions, avoiding the need for the exception to be declared in the throws clause or explicitly dealt with in a catch. This is an approach advocated by Josh Bloch in Effective Java, and used in the Java API, e.g. iterator.hasNext() being called before iterator.next().

Finally, exceptions should not be used in a situation where a return value can convey the same information. I have covered this topic in another blog post called ‘Exceptions versus return values‘.

CONCLUSION: USE CHECKED EXCEPTIONS, WITH CAUTION

Exceptions, including checked Exceptions, are a good idea, so long as they are used correctly. An Exception should be thrown when a method encounters a condition that it can’t handle itself. If the situation is not likely to be recoverable, throw an unchecked exception. If you can recover, throw a checked exception.