JavaDoc defines set as :
A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2)
To verify the same, i created a very simple program:
import java.util.HashSet;
public class CheckHashSet {
public static void main(String[] args) {
HashSet<Employee> set = new HashSet<Employee>();
set.add(new Employee(10));
set.add(new Employee(10));
System.out.println(set.size());
System.out.println(new Employee(10).equals(new Employee(10)));
}
private static class Employee implements Comparable<Employee> {
private final int id;
public Employee(int id) {
this.id = id;
}
@Override
public int compareTo(Employee o) {
return this.id - o.id;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Employee) {
return compareTo((Employee)obj)==0;
}
return false;
}
}
}
The output of the program is
2
true
This means new Employee(10).equals(new Employee(10))
returns true whereas set.add(new Employee(10)); set.add(new Employee(10));
adds the object twice.
What is wrong with my code?
Your class voilates the joint contract on
equals()
andhashCode()
:In your case, equal objects do not necessarily have equal hash codes. This is what's confusing the
HashSet
, sinceEmployees
with the sameid
could end up in different buckets and consequently get treated as if they weren't equal.To fix, override
hashCode()
[for example, to simply returnthis.id
].Maybe here is your problem
return this.id - o.id;
rather you checkreturn this.equals(o)
that return true or false.Your
Employee
class doesn't overridehashCode
- it needs to do so in order for any hash-based collection to work.For example:
HashSet
is based on Hash Table data structure so you have to override bothequals
andhashCode
methods in classEmployee
to make it work properly.However you can use another
Set
implementation not based on hash table such asTreeSet
.