Presents your JAVA E-NEWSLETTER for June 17, 2002 -------------------------------------------- EXAMINE THE CONTRACTUAL OBLIGATIONS OF THE COMPARATOR INTERFACE The java.util.Comparator interface is easy to implement and use, but there are a few parts of the Comparator javadoc that deserve a closer reading. Classes that implement the Comparator interface may be passed to methods, such as Collections.sort when sorting a List. They may also be used alongside a sorted set or map to ensure that that the set or map always retains a sorted order. TreeSet and TreeMap are such classes. Within the Comparator interface, only one method needs to be implemented: int compare(Object o1, Object o2); If o1 is considered to be less than o2, a negative number is returned. If o1 is greater than o2, a positive number is returned. When they are equal, the return is 0. This is all that usually needs to be done to handle comparisons, but there's more than this in the Comparator interface's contract. First, the compare method needs to be symmetric, meaning compare(a,b) provides the opposite result as compare(b,a). The opposite result indicates that the value returned has a differing sign or both are zero. However, it's legal for compare(a,b) to return 4 and compare(b,a) to return -2. While this is often the case, the Exceptions that the method throws must also be symmetric. If calling compare(a,b) throws a ClassCastException, then compare(b,a) must also throw a ClassCastException. Consider the following code snippet: public int compareTo(Object o1, Object o2) { if(o1 instanceof Long) { Long ln = (Long)o1; return ln.compareTo(o2); } else { return 0; } } If a is new Long(5) and b is "Text", then compare(o1,o2) will throw a ClassCastException in java.lang.Long's compareTo method, while compare(o1,o2) will return 0. Second, any Comparators that you plan to reuse should be Serializable. TreeSets and TreeMaps store the Comparator to handle comparisons, so in order for these two collections to be Serializable, the Comparator they use needs to be Serializable, as well. Third, Comparators should implement the equals method if they have multiple ways of comparing things. It's common for developers to create Comparators that have multiple forms of comparison, such as: import java.util.Comparator; public class ExampleComparator { private int type; public ExampleComparator(int i) { this.type = i; } public int compareTo(Object o1, Object o2) { if(type == 1) { // one type of comparison .... } else if(type == 2) { // another form of comparison .... } } } In this style of Comparator, the equals method needs to return true only when the 'type' of the Comparator is the same. For example: public boolean equals(Object obj) { if(obj instanceof ExampleComparator) { if( ((ExampleComparator)obj).type == this.type) ) { return true; } } return false; } The Comparator interface, ordinarily used in the Collections.sort, is an important part of Java to be aware of because it has some important contractual obligations that are often ignored. ----------------------------------------