I have the following code which will sort the Employees's
based on their experience.
I am adding 2 employees with different name
and same experience
. I am expecting that at the end set
will have 2 employees, but I am getting only one.
I have also overridden equals
and hashcode
, Can any one tell me why I am getting only one employee in the set.
Test Class
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.junit.Test;
public class SetWithComparator {
@Test
public void testComparatorWithSet() {
Comparator<Employee> comparator =
(emp1, emp2) -> emp1.getYearOFExp().compareTo(emp2.getYearOFExp());
Set<Employee> empSet = new TreeSet<>(comparator);
Employee e1 = new Employee();
e1.setName("Employee-1");
e1.setYearOFExp(12f);
Employee e2 = new Employee();
e2.setName("Employee-2");
e2.setYearOFExp(12f);
empSet.add(e1);
empSet.add(e2);
}
}
Model Class
class Employee {
private String name;
private Float yearOFExp;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getYearOFExp() {
return yearOFExp;
}
public void setYearOFExp(Float yearOFExp) {
this.yearOFExp = yearOFExp;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Employee) {
Employee e = (Employee) obj;
return new EqualsBuilder().append(name, e.getName()).isEquals();
} else {
return false;
}
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(name).toHashCode();
}
}
Because the comparator is not consistent with your equals method. Please check the documentation of Comparator.
The ordering imposed by a comparator c on a set of elements S is said to be consistent with equals if and only if c.compare(e1, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S.
Caution should be exercised when using a comparator capable of imposing an ordering inconsistent with equals to order a sorted set (or sorted map). Suppose a sorted set (or sorted map) with an explicit comparator c is used with elements (or keys) drawn from a set S. If the ordering imposed by c on S is inconsistent with equals, the sorted set (or sorted map) will behave "strangely." In particular the sorted set (or sorted map) will violate the general contract for set (or map), which is defined in terms of equals.
The exact behavior that you experience is hinted in the docs of Comparable (although you use comparator):
For example, if one adds two keys a and b such that (!a.equals(b) && a.compareTo(b) == 0) to a sorted set that does not use an explicit comparator, the second add operation returns false (and the size of the sorted set does not increase) because a and b are equivalent from the sorted set's perspective.
In your case: comparator.compare(e1, e2)
is 0
, e1.equals(e2)
is false
.
For a SortedSet
, the Comparator
determines what elements are the same and it won’t contain duplicates. If you don’t want to consider all employees with the same experience to be the same, you have to add a secondary ordering:
Comparator<Employee> comparator = Comparator.comparing(Employee::getYearOFExp)
.thenComparing(Employee::getName);
Note that you have to include all properties that make up the identity of an employee. In your example, there is only the name, however, in real life scenarios you would have more. On the other hand, if you have an ID, that determines the identity, you don’t need to check other properties and, in fact, shouldn’t, as most properties, including the name, can change. This also applies to the implementation of equals
and hashCode
.
In order to warn about false assumptions about what can be assumed to be granted, gender changes are a real life fact and even birthdays may turn out to be false and need a correction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With