Reputation: 11
I'm using TreeSet to save unique employees and sort by name. But I got strange results. Here is the code:
import java.util.Comparator;
import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeSet;
class Employee implements Comparable<Employee> {
private int id;
private String name;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// Two Employees are equal if their IDs are equal
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return id == employee.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
// Compare employees based on their IDs
@Override
public int compareTo(Employee employee) {
return this.getId() - employee.getId();
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) {
SortedSet<Employee> employees = new TreeSet<>();
// Providing a Custom Comparator (This comparator compares the employees based on their Name)
employees = new TreeSet<>(Comparator.comparing(Employee::getName));
employees.add(new Employee(1010, "Rajeev"));
employees.add(new Employee(1011, "Rajeev"));
employees.add(new Employee(1005, "Sachin"));
employees.add(new Employee(1008, "Chris"));
System.out.println("\nEmployees (sorted based on the supplied Comparator)");
System.out.println(employees);
}
}
Here is the output:
Employees (sorted based on the supplied Comparator)
[Employee{id=1008, name='Chris'}, Employee{id=1010, name='Rajeev'}, Employee{id=1005, name='Sachin'}]
I'm using openJDK-11.0.1_1_macosx. The object employees.add(new Employee(1011, "Rajeev")); was rejected. I thought it rejects the object with the duplicated employ.id but not the employ.name.
Thanks for your help.
Upvotes: 1
Views: 373
Reputation: 10964
From TreeSets
javadoc:
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 {@code Set} interface. (See {@code Comparable} or {@code Comparator} for a precise definition of consistent with equals.) This is so because the {@code Set} interface is defined in terms of the {@code equals} operation, but a {@code TreeSet} instance performs all element comparisons using its {@code compareTo} (or {@code 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 {@code Set} interface.
The Name-Comparator is not consistent with the equals implementation of Employee
as equals only checks for the employee id. That is the two "Rajeev" employees are equal from a comparator perspective but not from an equals perspective. To make this work as desired you should include the ID as second comparator criterium:
employees = new TreeSet<>(Comparator.comparing(Employee::getName)
.thenComparing(Employee::getId));
Upvotes: 4