22

I am trying to add two 'Employee' objects to a TreeSet:

Set<Employee> s = new TreeSet<Employee>();
s.add(new Employee(1001));
s.add(new Employee(1002));

But it throws a ClassCastException:

Exception in thread "main" java.lang.ClassCastException: Employee cannot be cast to java.lang.Comparable
    at java.util.TreeMap.put(TreeMap.java:542)
    at java.util.TreeSet.add(TreeSet.java:238)
    at MyClient.main(MyClient.java:9)

But if I add only one object to the TreeSet:

Set<Employee> s = new TreeSet<Employee>();
s.add(new Employee(1001));

Or if I use a HashSet instead:

Set<Employee> s = new HashSet<Employee>();
s.add(new Employee(1001));
s.add(new Employee(1002));

Then it is successful. Why does the exception happen and how do I fix it?

Boann
  • 48,794
  • 16
  • 117
  • 146
Rais Alam
  • 6,970
  • 12
  • 53
  • 84
  • 3
    You need to trust that the error message is correct. `Employee cannot be cast to java.lang.Comparable` is the problem. When you have one element there is nothing to compare so it doesn't detect the problem. HashSet doesn't use Comparable so it doesn't check it either. – Peter Lawrey Apr 11 '13 at 07:45

6 Answers6

26

Either Employee has to implement Comparable, or you need to provide a comparator when creating the TreeSet.

This is spelled out in the documentation for SortedSet:

All elements inserted into a sorted set must implement the Comparable interface (or be accepted by the specified comparator). Furthermore, all such elements must be mutually comparable: e1.compareTo(e2) (or comparator.compare(e1, e2)) must not throw a ClassCastException for any elements e1 and e2 in the sorted set. Attempts to violate this restriction will cause the offending method or constructor invocation to throw a ClassCastException.

If you don't fulfil these requirements, the sorted set won't know how to compare its elements and won't be able to function.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Ok so either Employee must implement comparable or i need to create an external comparator am I right? – Rais Alam Apr 11 '13 at 07:40
  • But in present case Employee class does not implements comparable and there is no External comparator. Every thing works fine when i ad one element. Problem starts when I add second element. Question is if the scenario you described is mandatory then why compiler compiles that program. – Rais Alam Apr 11 '13 at 07:44
  • @FireFly: It's mandatory, but is not enforced until the set actually needs to compare elements (which happens when you try to add the second element). – NPE Apr 11 '13 at 07:46
  • @FireFly: Without the external comparator, the class assumes the specialization parameter to implement Comparable interface. Either one must exist, but the compiler can't force such a constraint because it's not possible to do so at compile time. – LeleDumbo Apr 11 '13 at 07:49
  • @NPE Thanks for the answer explanation. I was asked in an interview and i failed to answer. – vijayraj34 Apr 16 '17 at 09:17
3

TreeSet requires elements to implement the Comparable interface if a custom Comparator is not set. HashSet uses the equals/hashCode contract instead.

You can add only one element into TreeSet which does not implement Comparable because it does not need to be compared with other elements.

Take a look at the TreeMap.put(K key, V value) source code and you'll clearly see the reasons behind all your questions (TreeSet is based on TreeMap, hence the source reference).

Boann
  • 48,794
  • 16
  • 117
  • 146
denis.solonenko
  • 11,645
  • 2
  • 28
  • 23
1

From TreeSet#add(E) JavaDoc:

Throws: ClassCastException - if the specified object cannot be compared with the elements currently in this set

Basically what you need is to let Employee implement Comparable or provide a Comparator to the TreeSet object.

If you check TreeMap code you will see that if the comparator wasn't found within the Map object, it will try to cast the key (your Employee object) directly to Comparator:

...
Comparable<? super K> k = (Comparable<? super K>) key;
...
Francisco Spaeth
  • 23,493
  • 7
  • 67
  • 106
0

So implement Comparable interface to Employee object as it`s needed when you are using TreeSet, because TreeSet wants to keep elements sorted.

Martin V.
  • 3,560
  • 6
  • 31
  • 47
0

TreeSet is an implementation of SortedSet. You can either let Employee implement the Comparable interface or provide an appropriate Comparator for your TreeSet:

Set<Employee> s = new TreeSet<Employee>(new EmployeeComparator());
igr
  • 10,199
  • 13
  • 65
  • 111
Marco Forberg
  • 2,634
  • 5
  • 22
  • 33
0
//class Employee
    public class Employee implements Comparable<Employee>{
    int id;

    Employee(int id){
    this.id=id;
    }

    public int compareTo(Employee e){ //implementing abstract method.
    if(id>e.id){
    return 1;
    }
    return 0;
    }


//class TreeSet

    Set<Employee> emp =new TreeSet<Employee>();

    Employee eobj1 = new Employee(2);
    Employee eobj2 = new Employee(3);
    emp.add(eobj1);
    emp.add(eobj2);

    for (Student ss:emp) {
    System.out.println(ss.rollno);
    }
}
//output: 2
//        3
charu
  • 9
  • 2