Most methods
and constructors have some restrictions on what values may be passed into their
parameters. For example, it is not uncommon that index values must be
non-negative and object references must be non-null. You should clearly
document all such restrictions and enforce them with checks at the beginning of
the method body.
If an invalid
parameter value is passed to a method and the method checks its parameters
before execution, it will fail quickly and cleanly with an appropriate
exception. If the method fails to check its parameters, several things could
happen.
For public
methods, use the Javadoc @throws tag to
document the exception that will be thrown if a restriction on parameter values
is violated (Item 62). Typically the exception will be IllegalArgumentException, IndexOutOfBoundsException, or NullPointerException (Item 60). Once you’ve documented
the restrictions on a method’s parameters and you’ve documented the exceptions
that will be thrown if these restrictions are violated, it is a simple matter
to enforce the restrictions. Here’s a typical example:
/**
* Returns a BigInteger whose value is (this mod m). This
method
* differs from the remainder method in that it always
returns a
* non-negative BigInteger.
*
* @param m the modulus, which must be positive
* @return this mod m
* @throws
ArithmeticException if m is less than or equal to 0
*/
public BigInteger
mod(BigInteger m) {
if (m.signum() <= 0)
throw new ArithmeticException("Modulus <= 0:
" + m);
... // Do the computation
}
Nonpublic
methods should generally check their parameters using assertions, as shown below:
// Private helper function for a recursive sort
private static
void sort(long a[], int offset, int length) {
assert a
!= null;
assert offset
>= 0 && offset <= a.length;
assert length
>= 0 && length <= a.length - offset;
... // Do the computation
}
In essence,
these assertions are claims that the asserted condition will be true, regardless of how the enclosing package is used by its
clients. Unlike normal validity checks, assertions throw AssertionError if they fail. And unlike normal validity
checks, they have no effect and essentially no cost unless you enable them,
which you do by passing the -ea (or -enableassertions) flag to the java
interpreter.
For more information on assertions, see Sun’s tutorial [Asserts].
It is
particularly important to check the validity of parameters that are not used by
a method but are stored away for later use.
Constructors
represent a special case of the principle that you should check the validity of
parameters that are to be stored away for later use. It is critical to check
the validity of constructor parameters to prevent the construction of an object
that violates its class invariants.
There are
exceptions to the rule that you should check a method’s parameters before
performing its computation. An important exception is the case in which the
validity check would be expensive or impractical and the validity
check is performed implicitly in the process of doing the computation. For
example, consider a method that sorts a list of objects, such as Collections.sort(List). All of the objects in the list
must be mutually comparable. In the process of sorting the list, every object
in the list will be compared to some other object in the list. If the
objects aren’t
mutually comparable, one of these comparisons will throw a Class- CastException,
which is exactly what the sort
method
should do. Therefore, there would be little point in checking ahead of time
that the elements in the list were mutually comparable. Note, however, that
indiscriminate reliance on implicit validity checks can result in a loss of
failure atomicity (Item 64).
To summarize,
each time you write a method or constructor, you should think about what
restrictions exist on its parameters. You should document these restrictions
and enforce them with explicit checks at the beginning of the method body. It
is important to get into the habit of doing this. The modest work that it
entails will be paid back with interest the first time a validity check fails.
Reference: Effective Java 2nd Edition by Joshua Bloch