user3366594
user3366594

Reputation:

I can't iterate through TreeSet

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

Answers (4)

Kakarot
Kakarot

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

ajb
ajb

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

Bosko Mijin
Bosko Mijin

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

Jigar Joshi
Jigar Joshi

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 Users can be compared

Upvotes: 2

Related Questions