You need to validate parameters passed to a method. You would prefer one line of code to test that a method parameter is valid.
Use Validate
to check method parameters.
Validate
can check for empty or
null
parameters, as well as evaluate any logical
conditions. Example 1-18 demonstrates the use of
Validate
to perform a few simple validations.
Example 1-18. Using Validate to perform simple validations
import org.apache.commons.lang.Validate; public doSomething( int param1, Object[] param2, Collection param3 ) { Validate.isTrue( param1 > 0, "param must be greater than zero" ); Validate.notEmpty( param2, "param2 must not be empty" ); Validate.notEmpty( param3, "param3 must not be empty" ); Validate.noNullElements( param3, "param3 cannot contain null elements" ); // do something complex and interesting }
Write finicky methods. Don’t just work with any
input, have some standards. Don’t hang around with
garbage or null
s—clean up your act, and use
Validate
. Methods in Validate
throw an IllegalArgumentException
if invalid
parameters are encountered. Validate.notEmpty( )
will throw an exception if the parameter is null
or empty, and Validate.isTrue( )
takes a logical
expression that must evaluate to true. Table 1-5
lists a number of static methods of Validate
.
Table 1-5. Available static methods on Validate
Validate method |
Description |
---|---|
|
Fails if expression evaluates to false |
|
Same as above; constructs exception with a message |
|
Fails if collection contains a null |
|
Fails if array contains a null |
|
Fails if collection is empty |
|
Fails if map is empty |
|
Fails if array is empty |
|
Fails if object is null |
Well-written code tests input and parameters. Is the number within a
given range? Has the user supplied an index that is out of bounds for
this array? Unless you want your applications to break down and throw
exceptions, make sure that you are not trying to access the 15th
element of a 10-element array; your code should be skeptical of
parameters and refuse to run if it doesn’t get its
way. In fragile systems, parameter validation is not a top priority;
errors are dealt with as different application layers throw a
potpourri of exceptions. Other, more unstable, systems will pass a
null
all the way down the call stack until the
lowest level blows up and spits back a
NullPointerException
—with a long-winded
stack trace. Don’t play around with
null
—avoid it, test your system
exhaustively, and throw an
IllegalArgumentException
.
Consider the following method, which takes a latitude, longitude, and
mode parameter. Both the latitude and longitude must fall within a
valid range, and this method should throw an
IllegalArgumentException
if it encounters an
unrealistic latitude, an unrealistic longitude, or an empty mode
parameter. The Validate
utility used in
conjunction with a DoubleRange
object can reduce
the amount of code dedicated to range checking and method parameter
validation. To test the validity of the coordinates, two constant
DoubleRange
objects are created outside of the
method. DoubleRange.includesDouble(double
d)
returns true if the number falls within the
defined range—if x <= rangeMax && x >= rangeMin
. (See Example 1-19.)
Example 1-19. Using the Validator and the DoubleRange to validate method parameters
public static final DoubleRange LAT_RANGE = new DoubleRange( -90.0, 90.0 ); public static final DoubleRange LON_RANGE = new DoubleRange( -180.0, 180.0 ); public double elevation( double latitude, double longitude, String mode ) { Validate.notEmpty( mode, "Mode cannot be empty or null" ); Validate.isTrue( LAT_RANGE.includesDouble( latitude ), "Lat not in range " + latRange, latitude ); Validate.isTrue( LON_RANGE.includesDouble( longitude ), "Lon not in range " + lonRange, longitude ); double elevation = 0.0; // code to implement the elevation method return elevation; }
It takes a fair amount of institutional discipline to make sure that
a code base has a sufficient amount of validation, and it is
surprising how often systems scale to thousands of lines without it.
Systems without good internal validation and sanity checks are
characterized by frequent occurrences of
NullPointerException
and
RuntimeException
. Throwing
RuntimeException
in the form of
IllegalArgumentException
might seem like an odd
recipe for increasing overall stability. But, if you actively throw
exceptions and test exhaustively, it will be less toil and trouble to
identify and fix defects—your application will fail sooner, and
you will have short stack traces and well-defined problems.
Performing rigorous parameter validation alone will not create a
stable system, but it is part of a larger equation, which involves
unit testing and validation.
In addition to parameter validation, you should be writing unit tests
that test this validation. If you write good unit tests using JUnit
and then measure your test coverage with a tool like Clover or
JCoverage, you can save yourself an amazing amount of grief fixing
unanticipated defects. Your unit tests should be covering close to
100% of your code, and they should throw curveballs.
Don’t just test the expected situation—if your
method takes a double, see what it does with
Double.POSITIVE_INFINITY
; and if your method takes
an array, pass it a null
. Test the unexpected; if
you find that your method melts down with a null
,
check the parameter with Validate
. 100% test
coverage is not an unrealistic ideal; it will drive your validation
code. More test coverage always leads to a higher level of system
quality.
Chapter 8 discusses
DoubleRange
and other utilities for capturing a
range of numbers.
Chapters 4 to Chapter 7 of the Java Extreme Programming
Cookbook by Eric Burke and Brian Coyner
(O’Reilly) are great introductions to unit testing
tools and concepts. Read this book for an introduction to JUnit,
HttpUnit, mock objects, and the idea of unit testing. Think of
Validate
as a runtime test for a method; the
methods on Validate
are analogous to the
assert( )
methods in JUnit’s
TestCase
class.
If you are interested in measuring code coverage of unit tests, take some time to look at Clover from Cortex eBusiness. Cortex eBusiness offers a free license to Open Source projects, but if you are using the product in a commercial environment, it is around $250. More information about Clover is available at http://www.thecortex.net/clover/. Other than Clover, there is another tool named JCoverage, which can also be used to measure test coverage. More information about JCoverage is available at http://www.jcoverage.com/. For more information about JUnit, go to http://www.junit.org/.
Get Jakarta Commons Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.