If I implement a custom comparator is it considered good practice to overide equals
besides compare
?
Additionally is there a defined contract for a Comparator
?

- 18,826
- 34
- 135
- 254
-
A common mistake is mutating a field used in hashCode, equals or compareTo. I would make them final and immutable where possible. – Peter Lawrey Oct 04 '12 at 09:30
-
Do you mean `Comparable`? (Or `compare`?) – Tom Hawtin - tackline Oct 04 '12 at 09:37
-
@TomHawtin-tackline:Updated OP – Jim Oct 04 '12 at 09:57
5 Answers
The javadoc for Comparator states:
The ordering imposed by a comparator c on a set of elements S is said to be consistent with equals if and only if c.compare(e1, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S.
Caution should be exercised when using a comparator capable of imposing an ordering inconsistent with equals to order a sorted set (or sorted map). Suppose a sorted set (or sorted map) with an explicit comparator c is used with elements (or keys) drawn from a set S. If the ordering imposed by c on S is inconsistent with equals, the sorted set (or sorted map) will behave "strangely." In particular the sorted set (or sorted map) will violate the general contract for set (or map), which is defined in terms of equals.
So the answer would be yes, it is good practice (for your first question at least).
-
What you quote does not say that it is good practice. It only states when equals and compareTo are consistent. – assylias Oct 04 '12 at 09:22
-
@assylias True, I added the second paragraph from the javadoc to make it clear. – maba Oct 04 '12 at 09:24
The contract of Comparator is defined in its javadoc. In particular:
Caution should be exercised when using a comparator capable of imposing an ordering inconsistent with equals to order a sorted set (or sorted map). Suppose a sorted set (or sorted map) with an explicit comparator c is used with elements (or keys) drawn from a set S. If the ordering imposed by c on S is inconsistent with equals, the sorted set (or sorted map) will behave "strangely." In particular the sorted set (or sorted map) will violate the general contract for set (or map), which is defined in terms of equals.
Typically, if 2 objects are equal from an equals
perspective but not from a compareTo
perspective, you can store both objects as keys in a TreeMap. This can lead to un-intuitive behaviour. It can also be done on purpose in specific situations.
For example, this answer shows an example where it is desirable that equals and compareTo be inconsistent.
I think you only have to override equals if you feel you are testing equality. Often when I write comparators they are comparing properties within an object and I continue to use the compareTo on these properties.
For example
public class ToCompare {
public static final Comparator<ToCompare> ID_COMPARATOR = new Comparator(){
@Override
public int compare(ToCompare o1, ToCompare o2) {
return o1.id.compareTo(o2.id);
}
}
private Integer id;
//... other fields here
}
I tend to store these comparators in the object as public static final fields to they are accessible from any code that may want to sort this object. If the object is updated (fields added/removed) then I can see straight away if there are problems with the comparator rather then going through all my code finding problems.

- 15,272
- 18
- 86
- 131
Yes. as suggested in java doc of Comparator I would say it will depend on your needs.
For example, suppose one adds two elements a and b such that (a.equals(b) && c.compare(a, b) != 0) to an empty TreeSet with comparator c. The second add operation will return true (and the size of the tree set will increase) because a and b are not equivalent from the tree set's perspective, even though this is contrary to the specification of the Set.add method.
But if you consider below example where you only have to sort particular list then you might don't have to.
Lets take an example of Class Employee
which has two properties id
, name
.
class Employee {
int id;// sample so access not considered
String name;// sample so access not considered
}
Suppose there are two separate options to sort list on id
or name
separately. In order to achieve this I would need to implement two comparators one which compares on id
and other which compares
on name.
Now if I want to implement comparator based on id
as its type is int
so wrapper type is Integer
and as Integer
provides compareTo
method just use it.
Same is the case of String
. This way you will have to hardly worry about writing compare
or compareTo
method.
I hardly need to think about while writing compare
method since I always use built in methods on properties of objects.
class EmpIdComparator implements Comparator<Employee> {
@Override
public int compare(Employee o1, Employee o2) {
return Integer.valueOf(o1.id).compareTo(o2.id);// Make use of
// existing
// comparators
// provided by java
}
}
class EmpNameComparator implements Comparator<Employee> {
@Override
public int compare(Employee o1, Employee o2) {
return o1.name == null ? o2.name == null ? 0 : 1 : o1.name
.compareTo(o2.name);// Make use of
// existing
// comparators
// provided by java
}
}

- 19,001
- 4
- 46
- 72
-
Should I take care of `null`?Isn't the contract to throw `NPE` for `null` arguments? – Jim Oct 04 '12 at 11:31
-
@Jim If comparator does not permit null then it should throw NPE other wise not. – Amit Deshpande Oct 04 '12 at 11:35
-
-
-
@Jim Answer to your first question :Java doc it self documents behaviour that way. For second question I have assumed that collection will not contain `null.` Should sort happen on collections containing null value is debatable. It is your choice. But check for properties is necessary since object might not be null be properties might be null. – Amit Deshpande Oct 04 '12 at 11:44
I feel that the other answers miss the point: Comparator
's compare-method compares the two given parameters, while a Comparator
's equals-method compares the Comparator
itself with another Object.
The javadoc for Comparator#equals
of at least newer JDKs explains it in detail:
/**
* Indicates whether some other object is "equal to" this
* comparator. This method must obey the general contract of
* {@link Object#equals(Object)}. Additionally, this method can return
* <tt>true</tt> <i>only</i> if the specified object is also a comparator
* and it imposes the same ordering as this comparator. Thus,
* <code>comp1.equals(comp2)</code> implies that <tt>sgn(comp1.compare(o1,
* o2))==sgn(comp2.compare(o1, o2))</tt> for every object reference
* <tt>o1</tt> and <tt>o2</tt>.<p>
*
* Note that it is <i>always</i> safe <i>not</i> to override
* <tt>Object.equals(Object)</tt>. However, overriding this method may,
* in some cases, improve performance by allowing programs to determine
* that two distinct comparators impose the same order.
*
* @param obj the reference object with which to compare.
* @return <code>true</code> only if the specified object is also
* a comparator and it imposes the same ordering as this
* comparator.
* @see Object#equals(Object)
* @see Object#hashCode()
*/
boolean equals(Object obj);
As such it is seldom useful to override the equals-method of Comparator
. Comparable
would be different, though.

- 1,471
- 13
- 16