Use overloading judiciously
The problem is that the two constructors have slightly different behavior, and thus violates the so-called "principle of least astonishment".
TreeSet(SortedSet<E>)
constructs a new set "using the same ordering as the specified sorted set," whereas TreeSet(Collection<? extends E>)
uses the "natural ordering of its elements." This means that two TreeSets constructed with the same underlying instance can act a bit different, depending on the static type of the reference they were constructed with.
SortedSet<Integer> original = getReverseSet(); // { 5, 4, 3, 2, 1}
Collection<Integer> alsoOriginal = original; // same instance exactly
TreeSet<Integer> a = new TreeSet<>(original);
TreeSet<Integer> b = new TreeSet<>(alsoOriginal);
It looks at first blush that a
and b
should be identical -- after all, they were constructed using the same exact instance! But the first uses the TreeSet(SortedSet)
constructor (and thus preserves the reverse ordering), while the second uses the TreeSet(Collection)
constructor (and thus uses the elements' natural ordering, which is different than the reverse ordering). In addition, a.comparator()
will return the reverse comparator, whereas b.comparator()
will return null.
This isn't wrong per se, but it can be surprising and confusing to users of your library!