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.)