Commons Lang CompareToBuilder
provides a builder for compareTo( )
methods. CompareToBuilder
can perform a comparison via reflection, or a comparison
can be customized by passing parameters to an instance of CompareToBuilder
. The following example
demonstrates the use of the reflection builder to implement a compareTo( )
method. This implementation
compares all nonstatic and nontransient member variables in both
classes.
import org.apache.commons.lang.builder.CompareToBuilder; // Build a compareTo function from reflection public int compareTo(Object o) { return CompareToBuilder.reflectionCompare(this, obj); }
CompareToBuilder.reflectionCompare(
)
takes two objects and compares the non-static, nontransient
member variables of these objects. In Example
1-2, the comparison involves the name properties of two PoliticalCandidate
objects from Example 1-3, which are considered equal if
both firstName
and lastName
are equal. reflectionCompare( )
ignores static fields and
transients; therefore, in Example 1-3,
averageAge
and fullName
do not contribute to the automated
comparison.
Example 1-3. Implementing compareTo( ) using a reflection builder
public class PoliticalCandidate implements Comparable { private String lastName; private String firstName; private transient String fullName; // Static Variable private static String averageAge; // Constructors // get/set methods // Build a compareTo function from reflection public int compareTo(Object o) { return CompareToBuilder.reflectionCompare(this, o); } }
In addition to a comparison by reflection, the CompareToBuilder
can be configured to compare
two objects by a set of variables in a particular order. The order of
comparisons plays a key role when a comparison involves multiple member
variables; this order is not specified when using the reflectionCompare()
method. Assume that the default sorting behavior for
PoliticalCandidate
objects should be
lastName
and then firstName
; if two objects have the same
lastName
, then sort by the firstName
. The following example demonstrates
a customization of the compareTo( )
method.
Calling append( )
specifies
what variables will be compared and in what order they will be compared.
The order of the calls to append( )
are backward—similar to pushing an object onto the top of a stack. The
last property "pushed" onto the CompareToBuilder
is the first property to be
compared. Objects are compared by last name, and first name is used as a
"tiebreaker." Example 1-4 will compare
two PoliticalCandidate
objects by
lastName
, falling back to firstName
only if the lastName
values were equal.
Example 1-4. Customizing a compareTo( ) method with CompareToBuilder
// A compare to that mimics the behavior of equals( ) public int compareTo(Object o) { int compare = -1; // By default return less-than if( o != null && PoliticalCandidate.class.isAssignableFrom( o.getClass( ) ) ) { PoliticalCandidate pc = (PoliticalCandidate) o; compare = (new CompareToBuilder( ) .append(firstName, pc.firstName) .append(lastName, pc.lastName)).toComparison( ); } return compare; }
Remember to keep the behavior of equals(
)
and compareTo( )
consistent to avoid problems when sorting collections. Automating the
compareTo( )
method via reflection
may not compare objects in a way that is consistent with equals( )
.
compareTo( )
methods provide
the natural sorting order for a set of objects, and they are frequently
used when sorting a collection of JavaBeans©. If you are trying to sort
a collection of beans, you are better off using the BeanComparator
, which is described in Recipe 3.10.
Instead of capturing comparison logic in a compareTo()
method, consider using a Comparator
object. The Commons Collections
project contains a number of supplements to the Comparator
interface, such as utilities to reverse and chain
comparators. Comparator
utilities are
discussed in Chapter 4.