Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Exceptions in Java: Nothing exceptional about them

Exception handling in Java from top to bottom

  • Print
  • Feedback

Page 3 of 5

A good example of an exceptional situation: If somehow the object instance -- which the search method invokes -- was null, this becomes a fundamental violation of the getPassenger methods' semantics. In order to understand the performance implications of exceptions, read the paragraph on performance.

How do I best use exceptions?

All Java developers must address the challenging task of catching different kinds of exceptions and knowing what to do with them. This grows even more complicated when the code must transform the error messages from cryptic system-level exceptions to more user-friendly application-level ones. This holds true particularly for API-type coding, where you plug your code into another application, and you don't own the GUI.

Typically, there are three approaches to handling exceptions:

  1. Catch and handle all the exceptions.
  2. Declare exceptions in the throws clause of the method and let them pass through.
  3. Catch exceptions and map them into a custom exception class and re-throw.


Let's look at some issues with each of those options and try to develop a practicable solution.

Case 1

Passenger getPassenger()
{
   try
   {
      Passenger flier = object.searchPassengerFlightRecord("John Doe");
   }
   catch(MalformedURLException ume)
   {
      //do something
   }
      catch(SQLException sqle)
      {
         //do something
      }
}


At one extreme, you could catch all exceptions and then find a way to signal the calling method that something is wrong. This approach, as illustrated in Case 1, needs to return null values or other special values to the calling method to signal the error.

As a design strategy, this approach presents significant disadvantages. You lose all compile-time support, and the calling method must take care in testing all possible return values. Also, the normal code and error-handling code blend together, which leads to cluttering.

Case 2

Passenger getPassenger() throws MalformedURLException, SQLException
{
   Passenger flier = object.searchPassengerFlightRecord("John Doe");
}


Case 2 presents the other extreme. The getPassenger() method declares all exceptions thrown by the method it calls in its throws clause. Thus getPassenger(), though aware of the exceptional situations, chooses not to deal with them and passes them on to its calling method. In short, it acts as a pass-through for the exceptions thrown by the methods it calls. However this does not offer a viable solution, as all responsibility for error processing is "bubbled up" -- or moves up the hierarchy -- which can present significant problems particularly in cases where multiple system boundaries exist. Pretend, for example, that you are Sabre (the airline reservation system), and the searchPassengerFlightRecord() method is part of your API to the user of your system, Travelocity.com, for example. The Travelocity application, which includes getPassenger() as part of its system, would have to deal with every exception that your system throws. Also, the application may not be interested in whether the exception is a MalformedURLException or SQLException, as it only cares for something like "Search failed." Let us investigate further by examining Case 3.

  • Print
  • Feedback

Resources