If I create an arbitrary class that does not implement Comparable, and try to use it as a treeset, it throws an exception at run time when an object is inserted:
public class Foo {
}
public TreeSet<Foo> fooSet = new TreeSet<Foo>();
fooSet.add(new Foo()); // Throws a ClassCastException exception here: Foo is not comparable
I'm no Java expert, but something about this seemed dynamically typed (ala Python) in a way I wasn't expecting. Is there no way for TreeSet's implementation to specify that its generic type argument must implement Comparable so that this can be caught at compile-time? Non-generic functions can take interfaces as arguments; is the same not possible with generics?
This error is thrown by TreeSet because TreeSet is used to store elements in sorted order and if the specified element cannot be compared with the elements currently in the set then TreeSet won't be able to store elements in sorted order and hence, TreeSet throws class cast exception.
The elements in TreeSet must be of a Comparable type. String and Wrapper classes are Comparable by default. To add user-defined objects in TreeSet, you need to implement the Comparable interface.
TreeSet does not allow to insert heterogeneous objects because it must compare objects to determine sort order. TreeSet is not synchronized. If multiple threads access a hash set concurrently, and at least one of the threads modifies the set, it must be synchronized externally.
TreeSet implements the SortedSet interface. So, duplicate values are not allowed and will be leftovers. Objects in a TreeSet are stored in a sorted and ascending order. TreeSet does not preserve the insertion order of elements but elements are sorted by keys.
TreeSet
is implemented that way because you can alternatively provide a Comparator
, in which case the elements don't need to be Comparable
. The only way to support both behaviors without splitting the implementation into multiple classes was to include runtime checks - this was simply a design decision by the author(s) of that class.
Exposing factory methods for TreeSet
instead of public constructors would've been a way to maintain compile time checks using stricter generic type constraints, but that would've been a break from the core collections API's convention of exposing public no-arg and copy constructors for its implementation classes. As you noted in your comment, Guava goes the factory route with its collections and IMHO is better off for it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With