TreeSet example

22,834

Solution 1

Your comparator function only uses fn:

public int compareTo(Student o) {
    return this.fn.compareTo(o.fn);
}

TreeSet only uses ordering comparisons - it doesn't use hashCode() and equals().

By this comparison, st1 and st3 are equal (s1.compareTo(s3) will return 0) therefore st3 isn't added to the set.

If you want to maintain the distinction, you should probably compare fn and then use ln if the fn values are the same:

public int compareTo(Student o) {
    int fnResult = this.fn.compareTo(o.fn);
    return fnResult == 0 ? ln.compareTo(o.ln) : fnResult;
}

Solution 2

Your observations are correct that TreeSet does not use .equals and .hashcode for comparison.

From the javadocs:

This is so because the Set interface is defined in terms of the equals operation, but a 
TreeSet instance performs all element comparisons using its compareTo (or compare) method,
so two elements that are deemed equal by this method are, from the standpoint of the set, 
equal. 

Basically, they are saying that for TreeSet, equality is determined not through .equals, but through .compareTo on the Comparable interface. Note that .compareTo should always be in line with .equals, meaning that if a.equals(b), then a.compareTo(b) == 0.

This has to do with the fact that TreeSet is an implementation of SortedSet. As such, it needs .compareTo in order to determine order, since .equals is not enough in that case.

PS: If you do not want to implement Comparable (which sometimes you can't since you might not always control the code of the objets), you could always pass a Comparator to the TreeSet constructor.

Share:
22,834
Girish
Author by

Girish

I am a confused developer who can code on Core Java, J2EE and also SAP ABAP with all errors!!!

Updated on July 09, 2022

Comments

  • Girish
    Girish almost 2 years

    Why the 3rd object is not being added to the treeset here though it is a different one?

    import java.util.*;
    
    class Student implements Comparable<Student>{
    public String fn,ln;
    public Student(String fn,String ln){
        this.fn=fn;
        this.ln=ln;
    }
    
    //overiding equals
    
    public boolean equals(Object o) {
        if (!(o instanceof Student))
            return false;
        Student s=(Student) o;
        if(this==s)
            return true;
        if(this.fn.equals(s.fn) && this.ln.equals(s.ln))
            return true;
        return false;
    }
    
    //overiding hashcode
    
    public int hashCode() {
        return fn.hashCode()+ln.hashCode();
    }
    
    
    //overiding compareTo
    
    public int compareTo(Student o) {
    
        return this.fn.compareTo(o.fn);
    }
      }
    
    public class Practice {
    
    
    public static void main(String[] args) {
        Student st1=new Student("Girish","J");
        Student st2=new Student("Master","M");
        Student st3=new Student("Girish","Jay");
        Set S=new TreeSet();
    
               //adding 3 different student objects
    
        System.out.println(S.add(st1));
        System.out.println(S.add(st2));
        System.out.println(S.add(st3));
        Iterator sitr=S.iterator();
        while(sitr.hasNext())
        {
            Student stu=(Student) sitr.next();
            System.out.println(stu.fn+" "+stu.ln);
        }
    
    
    }
    
     }
    

    Output:

    true
    true
    false
    Girish J
    Master M
    
  • Girish
    Girish about 12 years
    Thanks Jon. while debugging I observed that Treeset doesn't use hashcode() and equals() for comparing. Interesting! So there's no way where you want to compare only first name?
  • jmj
    jmj about 12 years
    +1 @Girish, You should have unique identifier for Student because it may happen where two students can have same first and last name
  • Jon Skeet
    Jon Skeet about 12 years
    Well you are only comparing first name. That's exactly what it's doing, which is why it's rejecting the third student. It's not clear what you want the requirements to be.
  • Girish
    Girish about 12 years
    @Jon: I was just learning the Collections by practising. No specific requirements as such.