Common Java Cookbook

Edition: 0.19

Download PDF or Read on Scribd

Download Examples (ZIP)

4.16. Modeling Loops with Closures

4.16.1. Problem

You need to execute a Closure multiple times.

4.16.2. Solution

Use a WhileClosure, passing in a Predicate and a Closure. The WhileClosure will execute the Closure as long as a Predicate evaluates to true. The following example demonstrates a Closure named drive, which operates on a Car object and a Predicate named hasFuel, which evaluates the Car object. Each time a Car is passed to drive, a gallon of fuel is used, and hasFuel will evaluate to true if the amount of fuel in a car is greater than zero. The WhileClosure, useAllFuel, evaluates drive until hasFuel evaluates to false:

import org.apache.commons.collections.Closure;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.functors.WhileClosure;
Closure drive = new Closure( ) {
    public void execute(Object input) {
        Car car = (Car) input;
        car.setFuel( car.getFuel( ) - 1 );
    }
}
Predicate hasFuel = new Predicate( ) {
    public boolean evaluate(Object object) {
        Car car = (Car) input;
        return car.getFuel( ) > 0;
    }
}
Closure useAllFuel = new WhileFuel( hasFuel, drive );
Car car = new Car( );
car.setMakeModel( "Ford Escort" );
car.setFuel( 20 );
System.out.println( "Car before while closure: " + car );
useAllFuel.execute( car );
System.out.println( "Car after while closure: " + car );

The WhileClosure, useAllFuel, takes a Car object, executing a Closure and evaluating a Predicate after every execution. The state of the car is printed both before and after it is passed to the WhileClosure:

Car before while closure: Ford Escort with 20 gallons of fuel.
Car after while closure: Ford Escort with no fuel.

4.16.3. Discussion

If you need to execute a Closure a set number of times, you can also use a ForClosure, passing in an int that specifies the number of times an object is passed to the execute( ) method of a Closure. This example uses the same Closure defined in the Solution, but, this time, the drive Closure is only executed five times:

               Closure driveSome = new ForClosure( 5, drive );
Car car = new Car( );
car.setMakeModel( "Toyota Camry" );
car.setFuel( 20 );
System.out.println( "Car before for closure: " + car );
driveSome.execute( car );
System.out.println( "Car after for closure: " + car );

Since the driveSome Closure is called only five times, the Camry still has 15 gallons after the ForClosure is executed:

Car before for closure: Toyota Camry with 20 gallons of fuel.
Car after for closure: Toyota Camry with 15 gallons of fuel.

Creative Commons License
Common Java Cookbook by Tim O'Brien is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License.
Permissions beyond the scope of this license may be available at http://www.discursive.com/books/cjcook/reference/jakartackbk-PREFACE-1.html. Copyright 2009. Common Java Cookbook Chunked HTML Output. Some Rights Reserved.