One of the
attributes that most strongly distinguishes expert programmers from less
experienced ones is that experts strive for and usually achieve a high degree
of code euse. Exceptions are no exception to the general rule that code reuse
is good. The Java platform libraries provide a basic set of unchecked
exceptions that cover a large fraction of the exception-throwing needs of most
APIs. In this item, we’ll discuss these commonly reused exceptions.
Reusing
preexisting exceptions has several benefits. Chief among these, it makes your
API easier to learn and use because it matches established conventions with
which programmers are already familiar. A close second is that programs using
your API are easier to read because they aren’t cluttered with unfamiliar
exceptions. Last (and least), fewer exception classes mean a smaller memory
footprint and less time spent loading classes.
The most
commonly reused exception is IllegalArgumentException. This s
generally the exception to throw when the caller passes in an argument whose
value is inappropriate. For example, this would be the exception to throw if
the caller passed a negative number in a parameter representing the number of
times some action was to be repeated.
Another
commonly reused exception is IllegalStateException. This is
generally the exception to throw if the invocation is illegal because of the
state of the receiving object. For example, this would be the exception to
throw if the caller attempted to use some object before it had been properly
initialized.
Arguably, all
erroneous method invocations boil down to an illegal argument or illegal state,
but other exceptions are standardly used for certain kinds of illegal arguments
and states. If a caller passes null in some
parameter for which null values are prohibited, convention dictates that NullPointerException be thrown rather than IllegalArgumentException. Similarly, if a caller passes
an out-ofrange value in a parameter representing an index into a sequence, IndexOutOf- BoundsException should be
thrown rather than IllegalArgumentException.
Another
general-purpose exception worth knowing about is ConcurrentModificationException. This
exception should be thrown if an object that was designed for use by a single
thread or with external synchronization detects that it is being (or has been)
concurrently modified.
A last
general-purpose exception worthy of note is UnsupportedOperation-Exception. This is the
exception to throw if an object does not support an attempted operation. Its
use is rare compared to the other exceptions discussed in this item, as most
objects support all the methods they implement. This exception is used by
implementations that fail to implement one or more optional operations defined
by an interface. For example, an append-only List
implementation
would throw this exception if someone tried to delete an element from the list.
Finally, be
aware that choosing which exception to reuse is not always an exact science, as
the occasions for use in the table above are not mutually exclusive. Consider,
for example, the case of an object representing a deck of ards. Suppose there
were a method to deal a hand from the deck that took as an argument the size of
the hand. Suppose the caller passed in this parameter a value that was larger
than the number of cards remaining in the deck. This could be construed as an IllegalArgumentException (the handSize parameter value is too high) or an IllegalStateException (the deck object contains too few
cards for the request). In this case the IllegalArgumentException
feels
right, but there are no hard-and-fast rules.
Reference: Effective Java 2nd Edition by Joshua Bloch