Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TreeSet violating Set contract?

I was trying to answer this question in the forum and I found that despite of overriding the equals method in the Employee class, I am still able to add duplicate elements to the TreeSet.

The Javadoc of TreeSet.add(E) method says

Adds the specified element to this set if it is not already present. More formally, adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false.

This essentially means that no 2 equals objects will be inserted into TreeSet and equality is determined solely by equals() method of contained objects.

However, below code is adding 2 elements to the Set even though they are equal

public class Employee implements Comparable<Employee> {

    String employeeName;
    int employeeId;

    public Employee(String name, int id) {
        this.employeeName = name;
        this.employeeId = id;
    }

    public int compareTo(Employee emp) {
        //return this.employeeName.compareTo(emp.employeeName);
        return (this.employeeId - emp.employeeId);
    }

    @Override
    public String toString() {
        return ("Name is: " + employeeName + " Emp id is: " + employeeId);
    }

    @Override
    public boolean equals(Object emp) {
        if(emp instanceof Employee &&((Employee)emp).employeeName.equals(this.employeeName)){
            return true;
        }
        return false;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Set<Employee> set = new TreeSet<Employee>();
        Employee e1 = new Employee("A", 1);
        Employee e2 = new Employee("A", 2);
        System.out.println(e1.equals(e2));
        set.add(e1);
        set.add(e2);
        System.out.println(set);
    }

}

And here is the output

true
[Name is: A Emp id is: 1, Name is: A Emp id is: 2]

Why is TreeSet allowing multiple elements even if they are equal?

Now I changed the compareTo method of Employee like this

public int compareTo(Employee emp) {
    return this.employeeName.compareTo(emp.employeeName);
}

And the output is

true
[Name is: A Emp id is: 1]

How the TreeSet working properly after overriding compareTo ?

like image 206
sanbhat Avatar asked Jul 19 '26 07:07

sanbhat


1 Answers

The javadoc of TreeSet also says:

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) 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. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

I agree that the javadoc of add() could make it clearer that equals() is not actually used, and re-state or link to this warning, though.

like image 74
JB Nizet Avatar answered Jul 20 '26 20:07

JB Nizet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!