You need to perform logic that is predicated on a certain condition being satisfied, and you want to encapsulate this condition in an object.
Use a Predicate to evaluate a
criteria or a condition. A Predicate
is an object that evaluates another object and returns true or false; predicates are used throughout the
Commons Collections packages for filtering, selecting, and validating
the contents of collections. This code demonstrates the use of simple
predicates to test the type and contents of an object:
import org.apache.commons.collection.Predicate; import org.apache.commons.collection.functors.*; String name = "Tim"; Predicate nameJohn = new EqualPredicate( "John" ); Predicate nameTim = new EqualPredicate( "Tim" ); Predicate instanceString = new InstanceofPredicate( String.class ); Predicate instanceDouble = new InstanceofPredicate( Double.class ); // Testing all predicates for "Tim" System.out.println( "Is Name John?: " + nameJohn.evaluate( name ) ); System.out.println( "Is Name Tim?: " + nameTim.evaluate( name ) ); System.out.println( "Is this a String?: " + instanceString.evaluate( name ) ); System.out.println( "Is this a Double?: " + instanceDouble.evaluate( name ) );
The previous example tests the name object against a few Predicate implementations producing the
following console output:
Is Name John?: false Is Name Tim?: true Is this a String?: true Is this a Double?: false
The string "Tim" is subjected to various Predicate tests. The first two EqualPredicate objects test the contents of
the string, returning true if the
object being evaluated is equal to the object passed into the EqualPredicate's constructor. The last two
Predicate objects are InstanceofPredicate instances, which test the
type of object being evaluated; if an InstanceofPredicate constructor is passed to
the String class, it returns true if the object being evaluated is a
java.lang.String type.
The simple Predicate interface
is central to a number of utilities introduced in this chapter. To
implement Predicate, define an
evaluate() method that returns a
boolean; a Predicate is a function object (or functor)
that captures a criteria in an object that can be created and altered at
runtime. Creating and evaluating a Predicate is just as valid as writing an
if statement; for example, the code
in the Solution of this recipe could have been implemented as a series
of if statements:
String name = "Tim";
if( name.equals( "John" ) ) {
System.out.println( "The name is John." );
}
if( name.equals( "Tim" ) ) {
System.out.println( "The name is Tim." );
}
if( name instanceof String ) ) {
System.out.println( "name is as String object" );
}
if( name instanceof Double ) ) {
System.out.println( "name is as Double object" );
}Predicate instances capture an
if statement in an object, and if you
are going to constantly change the behavior of your application, you
might want to consider placing conditional expressions in Predicate instances. For example, if a system
is designed to classify a storm as being a hurricane, you may want to
capture all of your classification criteria in an XML file—parsing this
file at runtime and creating a series of Predicate objects. A storm is a hurricane when
the winds exceed a certain value, and the barometric pressure falls
below a certain point. But, in a few years those criteria might change
to involve a new, or more complex, set of measurements. If your decision
logic is encapsulated in a Predicate
object, it will be easier to upgrade the program to take new criteria
into account; all of this logic will be encapsulated in an instance of
Predicate.
Commons Collections provides a number of basic predicates for
common situations, such as testing to see if an object equals another
object (EqualPredicate), or that an
object is of a certain type (InstanceofPredicate). Table 4-1 lists a number of simple
Predicate implementations.
Table 4-1. Predicate implementations
|
Name |
Description |
|---|---|
|
|
Compares each object to an object passed via a constructor—returning true if the two are equal. |
|
|
Returns true if the object being evaluated is the
same object reference as the object passed to its constructor.
The |
|
|
Wraps a |
|
|
Returns |
|
|
Returns true if the object being evaluated is
|
|
|
Returns true if the object being evaluated is not
|
|
|
Always returns |
|
|
Always returns |
|
|
Returns |
The following example demonstrates simple Predicate objects with
a test for equality, inequality, and equality by identity:
import org.apache.commons.collections.Predicate; import org.apache.commons.collections.functors.*; ... String testName = "Ben"; Predicate equals = new EqualPredicate( testName ); Predicate notEquals = new NotPredicate( equals ); Predicate identity = new IdentityPredicate( testName ); System.out.println( "Does name equal 'Ben'? " + equals.evaluate( "Ben" ) ); System.out.println( "Is object 'Ben'? " + identity.evaluate( testName ) ); System.out.println( "Does name equal 'Tim'? " + equals.evaluate( "Tim" ) ); System.out.println( "Does name not equal 'Tim'? " + notEquals. evaluate( "Tim" ) ); System.out.println( "Is object 'Tim'? " + identity.evaluate( "Tim" ) );
This code demonstrates the use of Predicate objects to determine if objects are
equal or if two object references reference the same instance. When
executed, the following is output to the console:
Does name equal 'Ben'? true Is object 'Ben'? true Does name equal 'Tim'? false Does name not equal 'Tim'? true Is object 'Tim'? false
The following code demonstrates simple predicates that test for
the presence or absence of null or if
an object being evaluated is of a certain type. The example also
demonstrates the use of a UniquePredicate that returns true when it encounters an object for the
first time:
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.functors.*;
String nullString = null;
Double testDouble = new Double(3.4);
Predicate isString = new InstanceofPredicate( String.class );
Predicate isLong = new InstanceofPredicate( Long.class );
Predicate isNumber = new InstanceofPredicate( Number.class );
Predicate isNotNull = NotNullPredicate.INSTANCE;
Predicate isNull = NullPredicate.INSTANCE;
Predicate unique = new UniquePredicate( );
System.out.println("'nullString' not null?: " + isNotNull.
evaluate(nullString));
System.out.println("'nullString' null?: " + isNull.evaluate(nullString));
System.out.println("'testDouble' a String?: " + isString.
evaluate(testDouble));
System.out.println("'testDouble' a Long?: " + isLong.evaluate(testDouble));
System.out.println("'testDouble' a Number?: " + isNumber.
evaluate(testDouble));
System.out.println("'A' Unique?: " + unique.evaluate("A"));
System.out.println("'C' Unique?: " + unique.evaluate("C"));
System.out.println("'A' Unique?: " + unique.evaluate("A"));
System.out.println("'B' Unique?: " + unique.evaluate("B"));The sample evaluates objects against the InstanceofPredicate, the NullPredicate, the NotNullPredicate, and the UniquePredicate, and the following is output
to the console:
'nullString' not null?: false 'nullString' null?: true 'testDouble' a String?: false 'testDouble' a Long?: false 'testDouble' a Number?: true 'A' Unique?: true 'C' Unique?: true 'A' Unique?: false 'B' Unique?: true
The UniquePredicate returns
false the second time it encounters
"A." The Double object testDouble is shown to be a Number object, and the nullString is evaluated as non-null.
This recipe mentions function pointers in C and C++. Function pointers are pointers to the address of a function, and they allow for some interesting logical acrobatics. For more information about function pointers in C and C++, see http://www.function-pointer.org/.
Predicate, Closure, and Transformer are all functor objects that are
used throughout the Commons Collections component. You may be familiar
with functors if you have used the Standard Template Library (STL) in
C++. STL documentation contains rigorous definitions for function
objects and
predicates. For more information about functors in STL, see http://www.sgi.com/tech/stl/functors.html.
