You need to iterate through
elements of a
Collection
that match a specified condition. Or,
you have a Collection
from which you need to
remove elements not satisfying a condition.
Create a
FilterIterator
with a Predicate
; if the
Predicate
returns true
for an
element, that element will be included in the
Iterator
. The FilterIterator
decorates another Iterator
and provides the
ability to apply an arbitrary filter to a
Collection
. In the following example,
EarthQuake
beans are kept in an
ArrayList
that is filtered using
the
majorQuakePredicate
and a
FilterIterator
:
import org.apache.commons.collection.Predicate; import org.apache.commons.collection.iterators.FilterIterator; List quakes = new ArrayList( ); EarthQuake quake1 = new EarthQuake( ); quake1.setLocation( "Chicago, IL" ); quake1.setIntensity( new Float( 6.4f ) ); quake1.setIntensity( new Float( 634.23f ) ); quake1.setTime( new Date( ) ); quakes.add( quake1 ); EarthQuake quake2 = new EarthQuake( ); quake2.setLocation( "San Francisco, CA" ); quake2.setIntensity( new Float( 4.4f ) ); quake2.setIntensity( new Float( 63.23f ) ); quake2.setTime( new Date( ) ); quakes.add( quake2 );Predicate majorQuakePredicate =
new MajorQuakePredicate( new Float(5.0), new Float(1000.0) );
Iterator majorQuakes =
new FilterIterator( quakes.iterator( ), majorQuakePredicate );
while( majorQuakes.hasMore( ) ) { EarthQuake quake = (EarthQuake) majorQuakes.next( ); System.out.println( "ALERT! MAJOR QUAKE: " + quake.getLocation( ) + ": " + quake.getIntensity( ) ); }
An instance of MajorQuakePredicate
is created, and
it is passed to a FilterIterator
. Quakes
satisfying the criteria are returned by the
FilterIterator
and printed to the console:
ALERT! MAJOR QUAKE: Chicago, IL: 6.4
The Solution uses a custom Predicate
to select a
subset of a Collection
, filtering
EarthQuake
beans and alerting the user if a major
earthquake is measured. An earthquake is classified by intensity on
the Richter scale and the depth of the epicenter; this information is
modeled by the
EarthQuake
bean defined in Example 5-1.
Example 5-1. An EarthQuake bean
package com.discursive.jccook.collections.predicates; public class EarthQuake { private String location; private Float intensity; private Float depth; private Date time; public class EarthQuake( ) {} public String getLocation( ) { return location; } public void setLocation(String location) { this.location = location; } public Float getIntensity( ) { return intensity; } public void setInsensity(Float intensity) { this.intensity = intensity; } public Float getDepth( ) { return depth; } public void setDepth(Float depth) { this.depth = depth; } public Date getTime( ) { return time; } public void setTime(Date time) { this.time = time; } }
An earthquake is considered major if it is above a five on the
Richter scale and above a depth of 1000 meters. To test each
EarthQuake
object, a custom
Predicate
, MajorQuakePredicate
,
evaluates EarthQuake
objects, returning
true
if an earthquake satisfies the criteria for a
major earthquake. The Predicate
defined in Example 5-2 encapsulates this decision logic.
Example 5-2. Major earthquake classification Predicate
package com.discursive.jccook.collections.predicates; import org.apache.commons.collections.Predicate; public class MajorQuakePredicate implements Predicate { private Float majorIntensity; private Float majorDepth; public MajorQuakePredicate(Float majorIntensity, Float majorDepth) { this.majorIntensity = majorIntensity; this.majorDepth = majorDepth; } public boolean evaluate(Object object) { private satisfies = false; if( object instanceof EarthQuake) { EarthQuake quake = (EarthQuake) object; if( quake.getIntensity( ).floatValue( ) > majorIntensity. floatValue( ) && quake.getDepth( ).floatValue( ) < majorDepth. floatValue( ) ) { satisfies = true; } } return satisfies; } }
If you want to create a Collection
of elements
that match a Predicate
, you can remove elements
from a Collection
using
CollectionUtils.filter( )
.
CollectionUtils.filter( )
is destructive; it
removes elements from a Collection
. The following
example demonstrates the use CollectionUtils.filter()
to remove nonmatching elements from a
Collection
:
import org.apache.commons.collection.Predicate; import org.apache.commons.collection.iterators.FilterIterator; ArrayList quakes = createQuakes( );Predicate majorQuakePredicate =
new MajorQuakePredicate( new Float(5.0), new Float(1000.0) );
CollectionUtils.filter( quakes, majorQuakePredicate );
After the execution of this code, quakes
will only
contain EarthQuake
objects that satisfy the
MajorQuakePredicate
.
If you don’t want to alter or modify an existing
Collection
, use CollectionUtils.select()
or CollectionUtils.selectRejected()
to create a new
Collection
with matching or nonmatching elements.
The following example demonstrates the use of
CollectionUtils.select( )
and
CollectionUtils.selectRejected( )
to select
elements from a Collection
leaving the original
Collection
unaffected:
import org.apache.commons.collection.Predicate; import org.apache.commons.collection.iterators.FilterIterator; ArrayList quakes = createQuakes( );Predicate majorQuakePredicate =
new MajorQuakePredicate( new Float(5.0), new Float(1000.0) );
Collection majorQuakes = CollectionUtils.select( quakes, majorQuakePredicate );
Collection minorQuakes =
CollectionUtils.selectRejected( quakes, majorQuakePredicate );
The majorQuakes
Collection
contains EarthQuake
objects satisfying the
majorQuakePredicate
, and the
minorQuakes
Collection
contains
EarthQuake
objects not satisfying the
majorQuakePredicate
. The quakes List
is not modified by select( )
or
selectRejected( )
.
Collections can be filtered via a combination
of
CollectionUtils
and Predicate
objects, or you can also select elements from a
Collection
using an XPath expression. Recipe 12.1 demonstrates the use on Commons JXPath to
query a Collection
.
3.142.42.176