Many of the JGL algorithms and containers require
you to specify a function object (sometimes known as a
functor) to perform their operation. A function object
can have instance variables and may be created and stored just
like any other kind of object. A function object that processes
one parameter is called a unary
function, whereas a function that processes two parameters is
called a binary function. There are two main types of function object:
boolean
,
and are used for ordering elements or triggering actions.
Object
.
The rest of this chapter describes predicates and
general functions in more detail.
Predicates are function objects that are used to
trigger actions or order elements, and always return a boolean
.
For example, the countIf()
algorithm allows you to count all of the values in a sequence
that satisfy a user-supplied unary predicate, and the sort()
algorithm orders the elements of a sequence using a user-supplied
binary predicate.
JGL defines interfaces for unary and binary predicates.
The UnaryPredicate
interface defines a single method called execute()
that takes a single Object
parameter and returns a boolean
.
The BinaryPredicate
interface defines a single method also called execute()
that takes two Object
parameters and returns a boolean
.
For example, here is the source code for the unary predicate object
PositiveInteger
:
package jgl; import jgl.UnaryPredicate; /** * PositiveInteger is a unary predicate that returns true if * its operand is positive. */ public final class PositiveInteger implements UnaryPredicate { /** * Return true if the operand is greater than zero. * @param object The operand, which must be an Integer. * @return object > 0 */ public boolean execute( Object object ) { return ((Integer) object).intValue() > 0; // Cast and test. } }
The following example uses PositiveInteger
to count the number of positive integers in a Vector
:
// Copyright(c) 1996 ObjectSpace, Inc.
import jgl.*;
public class Functions1
{
public static void main( String[] args )
{
Array array = new Array();
array.add( new Integer( 3 ) );
array.add( new Integer( -2 ) );
array.add( new Integer( 3 ) );
array.add( new Integer( -5 ) );
array.add( new Integer( -4 ) );
UnaryPredicate predicate = new PositiveInteger();
int n = Counting.countIf( array, predicate );
System.out.println( "Number of positive Integers in " + array + " = " + n );
}
}
Output
Number of positive Integers in Vector( 3, -2, 3, -5, -4 ) = 2
Another example is a unary predicate called LogicalNot
that returns true
if its single operand is false
.
The following example uses an instance of this class to count
all of the false
elements in a native Java array:
// Copyright(c) 1996 ObjectSpace, Inc.
import jgl.*;
public class Functions2
{
public static void main( String[] args )
{
boolean array[] = { false, false, true, false, true };
BooleanArray bools = new BooleanArray( array );
UnaryPredicate predicate = new LogicalNot();
int n = Counting.countIf( bools, predicate );
System.out.println( "Number of false in " + bools + " = " + n );
}
}
Output
Number of false in boolean[]( false, false, true, false, true ) = 3
Predicates are often used as a comparator for ordering
elements. An object A will be placed to the left of an
object B if the predicate object returns true
when executed with A as the first operand and B
as the second operand. Note that a properly designed comparator should
always return false when comparing two objects are are equal.
Here is the source code for an example
comparator, GreaterString
.
package jgl; import jgl.BinaryPredicate; /** * GreaterString is a binary predicate that returns true if the first operand * as a String is greater than the second operand as a String. */ public final class GreaterString implements BinaryPredicate { /** * Return true if the first operand is greater as a String than the second operand * as a String. * @param first The first operand, which is converted into a String if necessary. * @param second The second operand, which is converted into a String if necessary. * @return first.toString() > second.toString() */ public boolean execute( Object first, Object second ) { return first.toString().compareTo( second.toString() ) > 0; // Convert and test. } }
One variation of sort()
allows you to specify a function that is used to control the order
of sorting. In the following example, GreaterString
tells sort()
to place the first operand to the left of the second operand if
the first operand is greater than the second operand.
// Copyright(c) 1996 ObjectSpace, Inc.
import jgl.*;
public class Functions3
{
public static void main( String[] args )
{
Deque deque = new Deque();
deque.add( "cat" );
deque.add( "ape" );
deque.add( "dog" );
deque.add( "bat" );
System.out.println( "unsorted = " + deque );
BinaryPredicate comparator = new GreaterString();
Sorting.sort( deque, comparator );
System.out.println( "sorted = " + deque );
}
}
Output
unsorted = Deque( cat, ape, dog, bat )
sorted = Deque( dog, cat, bat, ape )
The next example uses the binary predicate LessInteger
to sort a native array of ints
.
// Copyright(c) 1996 ObjectSpace, Inc.
import jgl.*;
public class Functions4
{
public static void main( String[] args )
{
int array[] = { 3, 1, 5, -2, 7, 9 };
IntArray intArray = new IntArray( array );
BinaryPredicate comparator = new LessInteger();
System.out.println( "unsorted = " + intArray );
Sorting.sort( intArray, comparator );
System.out.println( "sorted = " + intArray );
}
}
Output
unsorted = int[]( 3, 1, 5, -2, 7, 9 ) sorted = int[]( -2, 1, 3, 5, 7, 9 )
For reference, here is a list of all the standard
JGL function predicate objects.
Unary Predicates
Name | Operation |
BindFirstPredicate
| P(V,x) |
BindSecondPredicate
| P(x,V) |
LogicalNot
| !x |
NegativeInteger
| x < 0 |
PositiveInteger
| x > 0 |
UnaryComposePredicate
| P(Q(x)) |
UnaryNot
| !P(x) |
Binary Predicates
Name | Operation |
BinaryComposePredicate
| P(Q(x), R(y)) |
BinaryNot
| !P(x, y) |
EqualTo
| x.equals( y ) |
GreaterEqualInteger
| x >= y |
GreaterEqualString
| x.toString().compareTo( y.toString() ) >= 0 |
GreaterInteger
| x > y |
GreaterString
| x.toString().compareTo( y.toString() ) > 0 |
HashComparator
| x.hashCode() < y.hashCode() |
IdenticalTo
| x == y |
LessEqualInteger
| x <= y |
LessEqualString
| x.toString().compareTo( y.toString() ) <= 0 |
LessInteger
| x < y |
LessString
| x.toString().compareTo( y.toString() ) < 0 |
LogicalAnd
| x && y |
LogicalOr
| x || y |
NotEqualTo
| !x.equals( y ) |
NotIdentical
| x != y |
In addition, here is a list of the standard JGL algorithms that
accept a predicate:
adjacentFind()
countIf()
detect()
every()
findIf()
includes()
makeHeap()
median()
nextPermutation()
popHeap()
prevPermutation()
pushHeap()
reject()
removeCopyIf()
removeIf()
replaceCopyIf()
replaceIf()
select()
setDifference()
setIntersection()
setSymmetricDifference()
setUnion()
some()
sort()
sortHeap()
unique()
uniqueCopy()
General functions are function objects that take
objects as parameters and return another object. They are often
used to apply a mathematical operation to every element in a collection.
JGL defines interfaces for unary and binary general functions.
The UnaryFunction
interface defines a single method called execute()
that takes a single Object
parameter and returns an Object
.
The BinaryFunction
interface defines a single method also called execute()
that takes two Object
parameters and returns an Object
.
For example, here's the source code of an example general function,
NegateInteger
.
package jgl; import jgl.UnaryFunction; /** * NegateInteger is a unary function object that assumes that its operand is * an instance of Integer and returns its negation. */ public final class NegateInteger implements UnaryFunction { /** * Return the negation of my operand. * @param object The operand, which must be an instance of Integer. * @return -object */ public Object execute( Object object ) { return new Integer( -((Integer) object).intValue() ); } }
This function object can be used by transform()
to negate every object in a sequence and store the result into
another sequence. The follow example uses NegateInteger
to negate every element in a Deque
:
// Copyright(c) 1996 ObjectSpace, Inc.
import jgl.*;
public class Functions5
{
public static void main( String[] args )
{
Deque deque = new Deque();
deque.add( new Integer( 4 ) );
deque.add( new Integer( -2 ) );
deque.add( new Integer( 3 ) );
UnaryFunction function = new NegateInteger();
System.out.println( "before = " + deque );
Transforming.transform( deque, deque.begin(), function );
System.out.println( "after = " + deque );
}
}
Output
before = Deque( 4, -2, 3 ) after = Deque( -4, 2, -3 )
For reference, here's a list of all the standard
JGL general functions. A later section explains how you can add
further variations of your own.
Unary Functions
Name | Operation |
BindFirst
| P(V,x) |
BindSecond
| P(x,V) |
Hash
| x.hashCode() |
LengthString
| x.toString().length() |
NegateInteger
| -x |
SelectFirst
| x.first |
SelectSecond
| x.second |
ToString
| x.toString() |
UnaryCompose
| P(Q(x)) |
UnaryPredicateFunction
| P(x) |
Binary Functions
Name | Operation |
BinaryCompose
| P(Q(x), R(y)) |
BinaryPredicateFunction
| P(x,y) |
DividesInteger
| x / y |
MinusInteger
| x - y |
ModulusInteger
| x % y |
PlusInteger
| x + y |
PlusString
| x.toString() + y.toString() |
TimesInteger
| x * x |
In addition, here's a list of all the standard JGL algorithms
that accept general functions:
transform()
adjacentDifference()
The predicate objects BindFirstPredicate
and BindSecondPredicate
allow you to give a fixed value to either the 1st or
the 2nd argument of a binary predicate, respectively.
For example, here's how you can use BindSecondPredicate
to count all of the strings in a DList
that are greater than "bat".
// Copyright(c) 1996 ObjectSpace, Inc.
import jgl.*;
public class Functions6
{
public static void main( String[] args )
{
DList list = new DList();
list.add( "dog" );
list.add( "ape" );
list.add( "emu" );
UnaryPredicate pred = new BindSecondPredicate( new GreaterString(), "bat" );
int n = Counting.countIf( list, pred );
System.out.println( "The number of strings in " + list + " > bat = " + n );
}
}
Output
The number of strings in DList( dog, ape, emu ) > bat = 2
The function objects BindFirst
and BindSecond
allow you to bind operands to general function objects.
The UnaryComposePredicate
and BinaryComposePredicate
function objects allow you to apply a secondary function to each
operand before applying the main predicate. For example, to sort
strings based on their length, use BinaryComposePredicate
as follows.
// Copyright(c) 1996 ObjectSpace, Inc.
import jgl.*;
public class Functions7
{
public static void main( String[] args )
{
Array array = new Array();
array.add( "ape" );
array.add( "giraffe" );
array.add( "lizard" );
BinaryPredicate comparator = new BinaryComposePredicate(
new GreaterInteger(), new LengthString(), new LengthString() );
System.out.println( "before = " + array );
Sorting.sort( array, comparator );
System.out.println( "after = " + array );
}
}
Output
before = Array( ape, giraffe, lizard ) after = Array( giraffe, lizard, ape )
The function objects UnaryCompose
and BinaryCompose
allow you to apply a secondary function to each operand before
applying the main general function.
To create your own function object, use the following rules:
UnaryPredicate
interface and define an execute()
method that takes one Object
argument and returns a boolean
.
BinaryPredicate
interface and define an execute()
method that takes two Object
arguments and returns a boolean
.
UnaryFunction
interface and define an execute()
method that takes one Object
argument and returns an Object
.
BinaryFunction
interface and define an execute()
method that takes two Object
arguments and returns an Object
.
Cast the input objects as necessary. If the method
must return a number or character, make sure a primitive value
is converted into its object equivalent using the primitive wrapper
classes in java.lang
.
Contents
Algorithms
Iterators