Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage News Effective Java Exceptions

Effective Java Exceptions

A new article by Barry Ruzek on BEA's dev2dev site discusses the use of exceptions in Java and proposes a way of thinking about exceptions to help guide when to use checked versus unchecked exceptions. It separates exceptional conditions into faults and contingencies and describes how to handle each.

Ruzek argues that those who say Java's checked exceptions are a failed experiment are wrong. The Java library designers failed to acknowledge the two basic causes for method failure, resulting in the overuse of checked exeptions. Ruzek posits that the two causes for method failure are:

  • Contingency - An expected condition demanding an alternative response from a method that can be expressed in terms of the method's intended purpose. The caller of the method expects these kinds of conditions and has a strategy for coping with them.
  • Fault - An unplanned condition that prevents a method from achieving its intended purpose that cannot be described without reference to the method's internal implementation.

In his example of a CheckingAccount class in a banking system, stop payment orders or overdrafts are contingencies, while the database being down or a network cable unplugged are faults. Based on this breakdown, contingencies should be handled with checked exceptions and faults with unchecked exceptions.

When processing faults, unchecked exceptions fits with the design of the JRE (ArithmeticException and ClassCastException are RuntimeException subclasses), and minimizes clutter because methods upstream of the fault do not all need to handle or explicitly pass the exception on. Furthermore, he suggests in most cases you can use RuntimeException itself, rather than a subclass. Most of the time you only need to pass on a message, as the exceptions are chained (from 1.4 on). Ruzek lists four goals for handling faults:

  • Minimize code clutter
  • Capture and preserve diagnostics
  • Alert the right person
  • Exit the activity gracefully

To handle faults, he recommends a fault barrier, which he describes here:

The goal here is to free the functional portions of your application from the responsibility of processing faults. Separation of concerns is generally a good thing, and a central facility responsible for dealing with faults will pay benefits down the road. In the fault barrier pattern, any application component can throw a fault exception, but only the component acting as the "fault barrier" catches them. Adopting this pattern eliminates much of the intricate code that developers insert locally to deal with faults. The fault barrier resides logically toward the top of the call stack where it stops the upward propagation of an exception before default action is triggered.

The fault barrier will log the information to the application log file and then close the operation in a controlled manner. For contingencies he recommends extending Exception to add value or information to the message passed back and not to bother with logging. He argues that since they are expected conditions, logging merely informs you that the application is working as designed. If a contingency represents a significant event, that should be logged before the exception is thrown.

Lastly, Ruzek points out that aspect oriented programming provides a excellent way to handle faults and contingencies, as they are cross-cutting concerns.

Rate this Article