The Artima Developer Community
Sponsored Link

Designing with Exceptions
When and How to Use Exceptions
by Bill Venners
First Published in JavaWorld, June 1998

<<  Page 4 of 5  >>


What to throw?
Once you have decided to throw an exception, you need to decide which exception to throw. You can throw an instance of class Throwable, or any subclass of Throwable. You can throw an already existing throwable object from the Java API, or define and throw one of your own. How do you decide?

Exceptions versus errors
In general, you should throw an exception and and never throw errors. Error, a subclass of Throwable, is intended for drastic problems, such as OutOfMemoryError, which would be reported by the JVM itself. On occasion an error, such as java.awt.AWTError, could be thrown by the Java API. In your code, however, you should restrict yourself to throwing exceptions (subclasses of class Exception). Leave the errors to the big guys.

Checked vs Unchecked exceptions
The big question, then, is whether to throw a "checked" or an "unchecked" exception. A checked exception is some subclass of Exception (or Exception itself), excluding class RuntimeException and its subclasses. Unchecked exceptions are RuntimeException and any of its subclasses. Class Error and its subclasses also are unchecked, but as you should be focusing on throwing exceptions only, your decision should be whether to throw a subclass of RuntimeException (an unchecked exception) or some other subclass of Exception (a checked exception).

If you throw a checked exception (and don't catch it), you will need to declare the exception in your method's throws clause. Client programmers who wish to call your method will then need to either catch and handle the exception within the body of their methods, or declare the exception in the throws clause of their methods. Making an exception checked forces client programmers to deal with the possibility that the exception will be thrown.

If you throw an unchecked exception, client programmers can decide whether to catch or disregard the exception, just as with checked exceptions. With an unchecked exception, however, the compiler doesn't force client programmers either to catch the exception or declare it in a throws clause. In fact, client programmers may not even know that the exception could be thrown. Either way, client programmers are less likely to think about what they should do in the event of an unchecked exception than they are in the case of an checked exception.

The simple guideline is:

If you are throwing an exception for an abnormal condition that you feel client programmers should consciously decide how to handle, throw a checked exception.

In general, exceptions that indicate an improper use of a class should be unchecked. The StringIndexOutOfBoundsException thrown by String's charAt() method is an unchecked exception. The designers of the String class didn't want to force client programmers to deal with the possibility of an invalid index parameter every time they called charAt(int index).

The read() method of class, on the other hand, throws IOException, which is a checked exception. This exception indicates some kind of error occurred while attempting to read from the file. It doesn't indicate that the client has used the FileInputStream class improperly. It just signals that the method itself is unable to fulfill its contractual responsibility of reading in the next byte from the file. The designers of the FileInputStream class considered this abnormal condition to be common enough, and important enough, to force client programmers to deal with it.

That is the trick, then, of deciding between a checked and an unchecked exception. If the abnormal condition is a failure of the method to fulfill its contract, and you feel it is common or important enough that client programmers should be forced to deal with the possibility of the exception, throw a checked exception. Otherwise, throw an unchecked exception.

Define a specific exception class
Finally, you must decide which exception class to instantiate and throw. The general rule here is to be specific. Don't just throw Exception, for example, with a string message indicating the kind of abnormal condition that caused the exception. Define or choose an already existing exception class for each kind of abnormal condition that may cause your method to throw an exception. This way, client programmers can define a separate catch clause for each kind of exception, or can catch some but not others, without having to query the object to determine the kind of abnormal condition that caused the exception.

You may wish to embed some information in the exception object, to give the catch clause more details about the exception. But you don't want to rely solely on embedded information to distinguish one type of exception from another. You don't want clients to have to query the exception object to determine, for example, whether the problem was an I/O error or an illegal argument.

Note that when String.charAt(int index) receives a bad input, it doesn't throw RuntimeException or even IllegalArgumentException. It throws StringIndexOutOfBoundsException. The type name indicates that the problem was a string index, and the program can query the object to find out what the bad index was.

<<  Page 4 of 5  >>

Sponsored Links

Copyright © 1996-2018 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use