Handling Errors using Exceptions |
When you design a package of Java classes that collaborate to provide some useful function to your users, you work hard to ensure that your classes interact well together and that their interfaces are easy to understand and program to. You should spend as much time thinking about and designing the exceptions that your classes throw as you do thinking about and designing the classes themselves.Suppose you were writing a linked list class that you were planning to distribute as freeware software. Among other methods, your linked list class supports these methods:
objectAt(int n)
- returns the object in the
n
th position in the list,firstObject()
- returns the first object in the list
indexOf(Object o)
- searches the list for the Object specified and returns its position in the list
What Can Go Wrong?
Because many programmers would be using your linked list class, you can be assured that many will misuse or abuse your class and its methods. Also, some legitimate calls to your linked list's methods may result in an undefined result. Regardless, in the face of errors, you want your linked list class to be as robust as possible under the circumstances, do something reasonable about the error, and communicate errors back to the calling program. However, you can't anticipate how each user of your linked list class will want the object to behave under adversity. So, often the best thing to do is to throw an exception.Each of the methods supported by your linked list may wish to throw an exception under certain conditions, and each method will probably throw a different type of exception than the others. For example,
But what type of exception should each method throw? Should it be an exception provided with the Java development environment? Or should you roll your own?
objectAt()
- will throw a exception if the integer passed into the method is less than 0 or larger than the number of object currently contained in the list
firstObject()
- will throw a exception if the list contains no objects
indexOf()
- will throw a exception if the object passed into the method is not contained in the list
Choosing the Exception Type to Throw
When faced with choosing the type of exception to throw, you have two choices:You should go to the trouble of writing your own exception classes if you answer "yes" to any of the following questions. Otherwise, you can probably get away with using someone else's:
- use one written by someone else. For example, the Java development enviroment provides a lot of exception classes that you could use.
- write one of your own
- Do you need an exception type that isn't represented by those in the Java development environment?
- Would it help your users if they could differentiate your exceptions from those thrown by classes written by other vendors?
- Does your code throw more than one related exception?
- If you use someone else's exceptions, will your users have access to those exceptions? A similar question is "Should your package be independent and self-contained?"
Your linked list class can throw multiple exceptions, and it would be convenient to be able to catch all exceptions thrown by the linked list with one handler. Also, if you plan on distributing your linked list in a package, all related code should be packaged together. Thus for the linked list, you should roll your own exception class hierarchy.
The following diagram illustrates one possible exception class hierarchy designed to support the linked list as described above:
LinkedListException is the parent class of all the possible exceptions that can be thrown by the linked list class. Users of your linked list class can write a single exception handler to handle all linked list exceptions with a
catch
statement like this:Or, users could write more specialized handlers for each subclass of LinkedListException.catch (LinkedListException) { . . . }Choosing a Superclass
The diagram above does not indicate the superclass of the LinkedListException class. As you know, Java exceptions must be Throwable objects (they must be instances of Throwable or a subclass of Throwable). So, your temptation might be to make LinkedListException a subclass of Throwable. However, the java.lang package provides two Throwable subclasses that further divide the type of problems that can occur within a Java program: Errors and Exceptions. Most of the applets and applications that you write will throw objects that are Exceptions. (Errors are reserved for serious hard errors that occur deep in the system.)Theoretically, any Exception subclass could be used as the parent class of LinkedListException. However, a quick perusal of those classes show that they are either too specialized or completely unrelated to LinkedListException to be appropriate. Thus, the parent class of LinkedListException should be Exception.
Because runtime exceptions don't have to be declared in the throws clause of a method, many packages developers ask: "Isn't it just easier if I make all of my exception inherit from RuntimeException?" The answer to this question is covered in detail on Runtime Exceptions--The Controversy. The bottom line is that you shouldn't derive from RuntimeException unless your class really is a runtime exception! For most of you, this means "No, your exceptions shouldn't inherit from RuntimeException."
Naming Conventions
It's good practice to append the word "Exception" to the end of all classes that inherit (directly or indirectly) from the Exception class. Similarly, classes that inherit from the Error class should end with the string "Error".
Handling Errors using Exceptions |