Oh no, what will happen if the general contract of Set is violated? Will the world end?
We can look at the API for TreeSet for a clue:
Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because 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.
(Emphasis mine)
Yes, it's violating the general contract, because it's relying on compareTo() instead of equals(). But it
is following its own contract. TreeSet will ignore equals() entirely, and use compareTo() or a Comparator instead. Which still produces perfectly usable, consistent results. They just don't make sense with the parts of the Set interface that mention the equals() method. Which is why we should ignore that, when using a TreeSet or TreeMap with a comparision that's inconsistent with equals(). The results will still make sense, according to the alternate definition of "equals()" that we supply with the Comparator or compareTo(). They warn us about it because it's something to be aware of, not because it's a deal breaker.
Let us also read from the Book of Joshua, 3:14 (p. 67 in 3rd Ed.):
Joshua Bloch wrote:It is strongly recommended, but not required, that (x.compareTo(y) == 0) == (x.equals(y)). Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is "Note: This class has a natural ordering that is inconsistent with equals."
And later on p. 68:
Joshua Bloch wrote:The final paragraph of the compareTo contract, which is a strong suggestion rather than a true requirement, simply states that the equality test imposed by compareTo method should generally return the same results as the equals method. If this provision is obeyed, the ordering imposed by the compareTo method is said to be consistent with equals. If it's violated, the ordering is said to be inconsistent with equals. A class whose compareTo method imposes an order that is inconsistent with equals will still work, but sorted collections containing elements of the class may not obey the general contract of the appropriate collection interfaces (Collection, Set, or Map). This is because the general contracts for those interfaces are defined in terms of the equals method, but sorted collections use the equality test imposed by comareTo instead of equals. It is not a catastrophe if this happens, but it's something to be aware of.
For BigDecimal, you can use a TreeSet or TreeMap just fine. You just have to decide whether you want the precision to be part of the comparison or not, and understand the consequences of that. The Set API only has one idea of how to compare two instances, by using equals. The TreeSet API allows more than one way, which you achieve by ignoring equals. It's OK.
Note that this is not like having a hashCode() method inconsistent with equals() - if you do that with a HashSet or HashMap, it may very well not work at all, being unable to find things that were inserted into it. Because HashSet and HashMap necessarily use
both hashCode() and equals() internally, and bad things happen when those do not agree. TreeSet And TreeMap, however, avoid this by not using equals()
at all, and instead using compareTo() or a Comparator. So they
do give consistent, useful results, even for "incompatible" comparison implementations... if we're not too paralyzed by fear to be able to use them.