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.
