Reputation:
I have to add User identified by his id into set and in runtime all users form that set have to be sorted by this id.
I've created TreeSet added some User objects and tried to iterate through it.
Here is my attempt:
//irrelevant code removed
TreeSet<User> userSet = new TreeSet<User>();
userSet.add(new User(2));
userSet.add(new User(1));
userSet.add(new User(3));
Iterator<User> iterator = userSet.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
I wrote class User where is one of the fields id and constructor have id as parameter.
public class User {
private int id;
// irrelevant code removed
public User(int id) {
this.id = id;
}
// irrelevant code removed
public String toString() {
return id + "";
}
}
When i run this code I get ClassCastException.
Here is the stacktrace:
Exception in thread "main" java.lang.ClassCastException: OrderedUsers$User cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1188)
at java.util.TreeMap.put(TreeMap.java:531)
at java.util.TreeSet.add(TreeSet.java:255)
at OrderedUsers.<init>(OrderedUsers.java:9)
at Main.main(Main.java:6)
What I am doing wrong?
Upvotes: 6
Views: 855
Reputation: 4252
TreeSet internally stores the object by performing comparasions with the existing ones similar to Binary Search Tree (actually its a Red-Black tree). So you need to implement interface Comparable in User or provide a custom Comparator to the TreeSet.
If you dont want the user objects to be stored in a sorted order I would recommend using ArrayList.
Method 1 :
public class User implements Comparable<User>
{
public int compare(User u)
{
if( u == null)
return 1;
return id - u.id;
}
}
Method 2 :
public class CompareUsers implements Comparator<User>
{
public int compareTo(User a, User b)
{
if(a == null)
return -1;
if(b == null)
return 1;
return a.id - b.id;
}
}
// Create an instance of this comparator class and pass to the TreeSet
// during initialization.
TreeSet<User> userSet = new TreeSet<User>(new CompareUsers());
Upvotes: 2
Reputation: 31699
Here's the statement at TreeMap.java 1188
:
return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
: comparator.compare((K)k1, (K)k2);
So if comparator
is null
, then it will try to cast the set member to a (Comparable)
. If your class doesn't implement Comparable
, this will cause the ClassCastException
you saw. comparator
is non-null only if you call the TreeMap
constructor that provides a Comparator
(or if you copy it from another SortedMap
that already has a comparator).
Upvotes: 2
Reputation: 3341
You are on the right way when you decided to use TreeSet because with TreeSet you can get ordered output. But...
Note that if you use TreeSet, because of TreeSet is sorted you have to implement Comparable
.
When you implement Comparable you will get what you expected.
I suggest that you perform changes like this:
public class User implements Comparable<User> {
private int id;
// irrelevant code removed
public User(int id) {
this.id = id;
}
// irrelevant code removed
public String toString() {
return id + "";
}
@Override
public int compareTo(User u) {
return id - u.id;
}
}
Upvotes: 4
Reputation: 240918
Either pass a custom Comparator
to TreeSet
constructor or implement Comparable
in your model class
TreeSet
maintains sorted order and it needs to know how User
s can be compared
Upvotes: 2