Can somebody put some light on what are the Consequences when compareTo()
is inconsistent with equals()
of a class. I have read that if Obj1.compareTo(Obj2) = 0
then it's not mandatory to be Obj1.equals(Obj2) = true
. But what is the consequence if this happens. Thanks.
-
not unless you make one – Sam I am says Reinstate Monica Mar 22 '13 at 14:30
-
@Sam I am can you be please more elaborative. – Trying Mar 22 '13 at 14:31
-
1The question is very vague. The consequence is "if you compare them in two different ways, you get two different answers" - the *follow-on* consequence depends on why you're performing that comparison. – Jon Skeet Mar 22 '13 at 14:32
-
for instance, i fyou typed a line like `if (Obj1.equals(Obj2) && Obj1.compareTo(Obj2)!= 0){throw new exception();}` then them being inconsistant would throw exceptions – Sam I am says Reinstate Monica Mar 22 '13 at 14:33
-
These issues i ran into a lot when had to implement a comparator. Equals did one thing but comparator absolutely another (i used it for sorting). One has to be carefull not to loose elements when implementing comparable. – Emil Iakoupov Mar 22 '13 at 14:38
-
possible duplicate of [Comparator best practice](http://stackoverflow.com/questions/12724051/comparator-best-practice) – assylias Mar 22 '13 at 14:43
-
1[BigDecimal](http://docs.oracle.com/javase/6/docs/api/java/math/BigDecimal.html#compareTo(java.math.BigDecimal)) is an example where it's not consistent. – Bhesh Gurung Mar 22 '13 at 15:02
3 Answers
The documentation for Comparable
explains this in some detail:
The natural ordering for a class
C
is said to be consistent withequals
if and only ife1.compareTo(e2) == 0
has the same boolean value ase1.equals(e2)
for everye1
ande2
of classC
. Note thatnull
is not an instance of any class, ande.compareTo(null)
should throw aNullPointerException
even thoughe.equals(null)
returnsfalse
.It is strongly recommended (though not required) that natural orderings be consistent with
equals
. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent withequals
. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of theequals
method.For example, if one adds two keys
a
andb
such that(!a.equals(b) && a.compareTo(b) == 0)
to a sorted set that does not use an explicit comparator, the second add operation returnsfalse
(and the size of the sorted set does not increase) becausea
andb
are equivalent from the sorted set's perspective.Virtually all Java core classes that implement
Comparable
have natural orderings that are consistent withequals
. One exception isjava.math.BigDecimal
, whose natural ordering equatesBigDecimal
objects with equal values and different precisions (such as4.0
and4.00
).
-
Example where it is useful to have `compareTo` inconsistent with `equals`: http://stackoverflow.com/questions/12587896/customizing-the-get-method-in-hashmap/12588005#12588005 – assylias Mar 22 '13 at 14:42
-
@NPE Can you please explain a bit this "In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method." with an example. I am not able to get it properly. thanks. – Trying Mar 22 '13 at 14:42
-
3@Trying: From the docs for `Set`: *sets contain no pair of elements e1 and e2 such that e1.equals(e2)*. On the other hand, a `SortedSet` (which must fulfil this contract because it is-a `Set`) uses `compareTo()` instead of `equals()`. Thus if your objects don't implement `compareTo/equals` consistently, and you put them in a `SortedSet`, you'll force the latter to break its contract. – NPE Mar 22 '13 at 14:53
Although the documentation says that consistency is not mandatory, it is better to always ensure this consistency, as you never know whether your object may be one day present in a TreeMap
/ TreeSet
or the like. If compareTo()
returns 0 for 2 objects that are not equal, then all Tree based collections are broken.
For example, imagine a class Query
, implementing an SQL query, with 2 fields:
- tableList: list of tables
- references: list of programs using such a query
Let's say that 2 objects are equal if their tableList is equal, i.e. the tableList
is the natural key of this object. hashCode()
and equals()
only consider the field tableList
:
public class Query implements Comparable {
List<String> tableList;
List<String> references;
Query(List<String> tableList, List<String> references) {
this.tableList = tableList;
this.references = references;
Collections.sort(tableList); // normalize
}
@Override
public int hashCode() {
int hash = 5;
hash = 53 * hash + Objects.hashCode(this.tableList);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Query other = (Query) obj;
return Objects.equals(this.tableList, other.tableList);
}
}
Let's say that we would like the sorting to be along the number of references.
Writing the code naively yields a compareTo()
methods which could look like this:
public int compareTo(Object o) {
Query other = (Query) o;
int s1 = references.size();
int s2 = other.references.size();
if (s1 == s2) {
return 0;
}
return s1 - s2;
}
Doing so seems OK as equality and sorting are done on two separate fields, so far so good.
However, whenever is put in a TreeSet
or a TreeMap
, it is catastrophic: the implementation of these classes consider that if compareTo returns 0, then the elements are equal. In this case, it would mean that each object with identical number of references are indeed 'equal' objects, which is obviously not the case.
A better compareTo()
method could be:
public int compareTo(Object o) {
Query other = (Query) o;
// important to match equals!!!
if (this.equals(other)) {
return 0;
}
int s1 = references.size();
int s2 = other.references.size();
if (s1 == s2) {
return -1; // not 0, they are NOT equal!
}
return s1 - s2;
}
Some collections will assume that if two objects follow obj1.compareTo(obj2) = 0
then obj1.equals(obj2)
is also true. For example: sorted TreeSet
.
Failing to meet this logic will result in an iconsistent collection. See:
Comparator and equals().

- 1
- 1

- 3,897
- 5
- 31
- 42