TreeSet giving incorrect output - Java8
Well, this surprised me, I don't know if I'm correct, but look at this implementation in AbstractSet
:
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
if (size() > c.size()) {
for (Iterator<?> i = c.iterator(); i.hasNext(); )
modified |= remove(i.next());
} else {
for (Iterator<?> i = iterator(); i.hasNext(); ) {
if (c.contains(i.next())) {
i.remove();
modified = true;
}
}
}
return modified;
}
Basically in your example, the size of set is equal to the size of arguments you want to remove, so the else condition is invoked. In that condition there is a check if your collection of arguments to remove contains
the current element of iterator, and that check is case sensitive, so it checks if c.contains("a")
and it returns false, because c
contains "A"
, not "a"
, so the element is not removed. Notice that when you add an element to your set s.addAll(Arrays.asList("a", "b", "d"));
it works correctly, because size() > c.size()
is now true, thus there is no contains
check anymore.
This happens because a SortedSet’s Comparator is used for sorting, but removeAll relies on the equals
method of each element. From the SortedSet documentation:
Note that the ordering maintained by a sorted set (whether or not an explicit comparator is provided) must be consistent with equals if the sorted set is to correctly implement the
Set
interface. (See theComparable
interface orComparator
interface for a precise definition of consistent with equals.) This is so because theSet
interface is defined in terms of theequals
operation, but a sorted set performs all element comparisons using itscompareTo
(orcompare
) method, so two elements that are deemed equal by this method are, from the standpoint of the sorted set, equal. The behavior of a sorted set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of theSet
interface.
The explanation of “consistent with equals” is defined in the Comparable documentation:
The natural ordering for a class
C
is said to be consistent with equals 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 with equals. 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.
In summary, your Set’s Comparator behaves differently than the elements’ equals
method, causing unusual (though predictable) behavior.