Saturday, October 31, 2009

Item 42:Favor the use of standard exceptions




< BACKCONTINUE >


Item 42:Favor the use of standard exceptions


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 reuse. 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. Finally, fewer exception classes mean a smaller memory footprint and less time spent loading classes.



The most commonly reused exception is IllegalArgumentException. This is 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 were to be repeated.



Another commonly reused exception is IllegalStateException. This is generally the exception to throw if the invocation is illegal, given 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-of-range value in a parameter representing an index into a sequence, IndexOutOfBoundsException should be thrown rather than IllegalArgumentException.



Another general-purpose exception worth knowing about is ConcurrentModificationException. This exception should be thrown if an object 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 UnsupportedOperationException. This is the exception to throw if an object does not support an attempted operation. Its use is rare compared to that of other exceptions discussed in this item, as most objects support all the methods they implement. This exception is used by implementations of interfaces that fail to implement one or more optional operations defined by the interface. For example, an append-only List implementation would throw this exception if someone tried to delete an element.



Table 8.1 summarizes the most commonly reused exceptions.


































Table�8.1. Commonly Used Exceptions

Exception

Occasion for Use

IllegalArgumentException

Parameter value is inappropriate

IllegalStateException

Object state is inappropriate for method invocation

NullPointerException

Parameter value is null where prohibited

IndexOutOfBoundsException

Index parameter value is out of range

ConcurrentModificationException

Concurrent modification of object has been detected where prohibited

UnsupportedOperationException

Object does not support method



While these are by far are the most commonly reused exceptions in the Java platform libraries, other exceptions may be reused where circumstances warrant. For example, it would be appropriate to reuse ArithmeticException and NumberFormatException if you were implementing arithmetic objects like complex numbers or matrices. If an exception fits your needs, go ahead and use it, but only if the conditions under which you would throw it are consistent with the exception's documentation. Reuse must be based on semantics, not just on name. Also, feel free to subclass an existing exception if you want to add a bit more failure-capture information (Item 45).



Finally, be aware that choosing which exception to reuse is not always an exact science, as the "occasions for use" in the Table 8.1 are not mutually exclusive. Consider, for example, the case of an object representing a deck of cards. 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.





< BACKCONTINUE >

No comments: