Suppose the following API:
final class Foo {
int bar;
Foo(int bar) { this.bar = bar; }
public int hashCode() {
return bar;
}
public boolean equals(Object o) {
return o instanceof Foo && ((Foo)o).bar == bar;
}
}
static Set<Foo> getSetOpaquely() {???}
I don't know where the Set comes from, just that I need to use it.
Suppose I assume the Set is like HashSet and defined in terms of equals
.
They also give an example of a "strange" behaviour when (a.equals(b) && c.compare(a,b) != 0)
Suppose I do
Set<Foo> mySet = getSetOpaquely();
mySet.add(new Foo(1));
System.out.println(mySet.add(new Foo(1));
Suppose my surprise when this prints true
because it was a TreeSet with a Comparator
(lhs, rhs) -> lhs == rhs ? 0 : 1
Now, can someone give me an example of a "strange" behavour in case (!a.equals(b) && c.compare(a,b) == 0)
?
Suppose I do
Set<Foo> mySet = getSetOpaquely();
mySet.add(new Foo(102));
System.out.println(mySet.add(new Foo(12));
Suppose my surprise when this prints false
because it was a TreeSet with a Comparator
(lhs, rhs) -> Integer.compare(lhs.bar % 10, rhs.bar % 10)
Now, there isn't an inherent problem with defining ordering that is inconsistent with equals
. The point is that a TreeSet might behave other than specified in the documentation for Set.
This is clearly documented:
[...] the Set
interface is defined in terms of the equals operation, but a TreeSet
instance performs all element comparisons using its compareTo
(or compare
) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set
interface.
As long as the Comparator isn't hacky and you know that it's a TreeSet with a particular ordering, you won't be surprised. (If it's hacky like (lhs, rhs) -> 1
you might be surprised.)