4.8. Writing a Custom Predicate

Problem

You need to evaluate an object to see if it meets criteria, and you want to capture these criteria in a custom Predicate.

Solution

Implement the Predicate interface and capture your logic in an evaluate( ) method. Example 4-5 is a simple Predicate implementation that always returns true; it is intended as a basic example of how to implement the Predicate interface.

Example 4-5. A simple Predicate implementation

import org.apache.commons.collections.Predicate;

public class SimplePredicate implements Predicate {
    public boolean evaluate(Object object) {
        // do something.
        boolean result = true;
        return result;
    }
}

Discussion

Predicates can be used in any number of situations, such as validating user input, filtering a Collection, or just as a replacement for complex conditional logic. A Predicate can be as simple or as complex as you need it to be; the only contract it must satisfy is the production of a boolean result from an evaluate( ) method.

To demonstrate the process of writing a fairly complex implementation of the Predicate interface, a contrived example is developed in Example 4-6. Your application evaluates the condition of the space shuttle and makes a determination for launch—go or no go. Some of the criteria include the temperature of the launch pad, the status of the crew, and the presence (or absence) of fuel. In the end, your boss is looking for thumbs up or thumbs down, and you decide to write a program that returns a boolean decision. This decision is implemented in the LaunchPredicate class.

Example 4-6. Implementing the Predicate interface

package com.discursive.jccook.collections.predicate;

import org.apache.commons.collections.Predicate;

public class LaunchPredicate implements Predicate {

    public LaunchPredicate( ) {}

    public boolean evaluate(Object object) {
        boolean launchGo = false;

        LaunchStats stats = (LaunchStats) object;

        boolean crewReady = stats.isCrewPresent( ) && stats.isCrewHealthy( );
        boolean fueled = stats.isShuttleFueled( ) && stats.
        isFuelIgnitionReady( );
        boolean withinLaunchWindow = stats.isLaunchWindowOpen( );

        boolean properWeather = 
                ( stats.temperature( ) > 35 ) && 
              ( !stats.isLightningDangerPresent( ) );

        // Check the crew, fuel, and launch time
            if( crewReady && fueled && withinLaunchWindow ) {
            launchGo = true;
        }

        // Override a GO decision if the weather is bad
        if( !properWeather ) {
            launchGo = false;
        }

        return launchGo;
    }
}

A shuttle launch is predicated on the presence and health of the crew, the state of the fuel, and the time of the launch event. A final weather check is performed to ensure that the temperature of the shuttle is not below 35 degrees Fahrenheit. If this critical temperature limit is not met, the Predicate overrides the previous decision to launch. Using a LaunchPredicate encapsulates your decision logic in one object, making it easier to upgrade, maintain, and test this decision process. Your unit tests can pass a mock object to this predicate, testing every possible permutation of possible inputs. The following example demonstrates the use of the LaunchPredicate:

LaunchPredicate launchDecision = new LaunchPredicate( );

LaunchStats stats = measureLaunchStatistics( );

if( launchDecision.evaluate( stats ) ) {
    System.out.println( "We are Go for Ignition." );
} else {
    System.out.println( "Abort mission." );
}

See Also

The real Space Shuttle Launch Team has the outrageously complex job of monitoring and controlling every aspect of launching a spacecraft, and I’m sure that NASA doesn’t implement the Predicate interface from Jakarta Commons Collections. While it isn’t related to the topic of open source Java programming, it is a fascinatingly complex piece of software that maintains a shuttle launch. It is written in something called high-order assembly language/shuttle (HAL/S). If you are interested in learning more about one of the most complex pieces of software, take a look at NASA’s Space Shuttle Launch Team website at http://science.ksc.nasa.gov/shuttle/countdown/launch-team.html. (Besides, I’m sure you are amused that NASA controls spacecraft with an assembly language known as HAL.)

This recipe mentions the use of a mock object to test a Predicate. One of the attractions of using a Predicate to encapsulate any complex condition is the ability to write a test for this condition logic; mock objects are a method of unit testing that involves passing a mock implementation of an object to a class i n a test. For more information about mock objects, see http://www.mockobjects.com/.

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.