The first lines of a method are usually devoted to checking the validity of method arguments. The idea is to fail as quickly as possible in the event of an error. This is particularly important for constructors.
It is a reasonable policy for a class to skip validating arguments of private methods. The reason is that private methods can only be called from the class itself. Thus, a class author should be able to confirm that all calls of a private method are valid. If desired, the assert keyword can be used to verify private method arguments, to check the internal consistency of the class. (Using assert for checking the arguments of a non-private method is not recommended, since disabling such assertions would mean the contract of the non-private method is no longer being enforced.)
When validating an argument, an Exception is thrown if the test fails. This is often IllegalArgumentException, NullPointerException, or IllegalStateException. These are all subclasses of RuntimeException. Checked exceptions may also be thrown, as shown in the Model Object validation topic. Many programmers document these exceptions in the @throws clause of the method's javadoc, since they clearly state the method's requirements to the caller (the pre-conditions). Others, however, feel that manually documenting exceptions should be avoided.
If every object parameter of every method in a class needs to be non-null in order to avoid throwing NullPointerException, then it's acceptable to state this once in the general class javadoc, instead of repeating it for each method.
Another alternative is to state in overview.html (javadoc's summary description of an entire application) that all parameters are to be considered non-null unless explicitly stated otherwise.
Example 1
The constructor of this class validates its arguments before doing anything
else. If a validation fails, then an IllegalArgumentException
is thrown.
public final class ElementaryParticle { /** * @param aName has content. * @param aSpeed is in the range 0 (inclusive) to 1 (inclusive), and * is expressed as a fraction of the speed of light. (The photon is * an example of an elementary particle which travels at this speed.) * @exception IllegalArgumentException if a param does not comply. */ public ElementaryParticle ( String aName, double aSpeed ) { if ( !textHasContent(aName) ) { throw new IllegalArgumentException("Name has no content."); } if ( aSpeed < 0.0 || aSpeed > 1.0 ) { throw new IllegalArgumentException("Speed not in range [0..1]: " + aSpeed); } fName = aName; fSpeed = aSpeed; } //..other methods elided // PRIVATE //// private String fName; private double fSpeed; /** * Returns true if aText is non-null and has visible content. * * This is a test which is often performed, and should probably * be placed in a general utility class. */ private boolean textHasContent( String aText ){ String EMPTY_STRING = ""; return (aText != null) && (!aText.trim().equals(EMPTY_STRING)); } }
Example 2
Some validations are very common :
- check that an object is not null
- check that text has visible content
- check that a number is in some range
package hirondelle.web4j.util; import java.util.regex.*; /** * Utility methods for common argument validations. * *<P>Replaces <tt>if</tt> statements at the start of a method with * more compact method calls. * * <P>Example use case. * <P>Instead of : * <PRE> * public void doThis(String aText){ * if (!Util.textHasContent(aText)){ * throw new IllegalArgumentException(); * } * //..main body elided * } * </PRE> * <P>One may instead write : * <PRE> * public void doThis(String aText){ * Args.checkForContent(aText); * //..main body elided * } * </PRE> */ public final class Args { /** * If <code>aText</code> does not satisfy {@link Util#textHasContent}, then * throw an <code>IllegalArgumentException</code>. * * <P>Most text used in an application is meaningful only if it has visible content. */ public static void checkForContent(String aText){ if( ! Util.textHasContent(aText) ){ throw new IllegalArgumentException("Text has no visible content"); } } /** * If {@link Util#isInRange} returns <code>false</code>, then * throw an <code>IllegalArgumentException</code>. * * @param aLow is less than or equal to <code>aHigh</code>. */ public static void checkForRange( int aNumber, int aLow, int aHigh ) { if ( ! Util.isInRange(aNumber, aLow, aHigh) ) { throw new IllegalArgumentException(aNumber + " not in range " + aLow + ".." + aHigh); } } /** * If <tt>aNumber</tt> is less than <tt>1</tt>, then throw an * <tt>IllegalArgumentException</tt>. */ public static void checkForPositive(int aNumber) { if (aNumber < 1) { throw new IllegalArgumentException(aNumber + " is less than 1"); } } /** * If {@link Util#matches} returns <tt>false</tt>, then * throw an <code>IllegalArgumentException</code>. */ public static void checkForMatch(Pattern aPattern, String aText){ if ( ! Util.matches(aPattern, aText) ){ throw new IllegalArgumentException( "Text " + Util.quote(aText) + " does not match '" +aPattern.pattern()+ "'" ); } } /** * If <code>aObject</code> is null, then throw a <code>NullPointerException</code>. * * <P>Use cases : <pre> doSomething( Football aBall ){ //1. call some method on the argument : //if aBall is null, then exception is automatically thrown, so //there is no need for an explicit check for null. aBall.inflate(); //2. assign to a corresponding field (common in constructors): //if aBall is null, no exception is immediately thrown, so //an explicit check for null may be useful here Args.checkForNull( aBall ); fBall = aBall; //3. pass on to some other method as parameter : //it may or may not be appropriate to have an explicit check //for null here, according the needs of the problem Args.checkForNull( aBall ); //?? fReferee.verify( aBall ); } </pre> */ public static void checkForNull(Object aObject) { if ( aObject == null ) { throw new NullPointerException(); } } // PRIVATE // private Args(){ //empty - prevent construction } }
Javadoc all exceptions
Assert is for private arguments only
Avoid @throws in javadoc
Model Objects
|
|