user3244519
user3244519

Reputation: 681

Duplicate custom objects are getting added to Hashset

I have an Employee class having 2 attributes id and name. I am overriding the hashcode and equals method as given below.

Employee.java:

import java.util.Objects;

public class Employee {

    private int id;
    private String 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;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (id != other.id)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + "]";
    }
}

And now i have a test class where i am creating an object of employee class with name "Chris Gayle" and adding it to HashSet. After that i am modifying the name of this existing employee object to "Kieron Pollard" and i am adding this modified employee object again to hashset.

TestSet.java

import java.util.HashSet;
import java.util.Set;

public class TestSet {

 public static void main(String[] args) {
     Set<Employee> hashSet = new HashSet<Employee>();

     Employee emp1 = new Employee();
     emp1.setId(1);
     emp1.setName("Chris Gayle");

     hashSet.add(emp1);

     System.out.println(hashSet);

     emp1.setName("Kieron Pollard");
     hashSet.add(emp1);
     System.out.println(hashSet.size());
     System.out.println(hashSet);
}

}

When i print the content of hashset i gives the same employee object two times as given below.

[Employee [id=1, name=Chris Gayle]]
2
[Employee [id=1, name=Kieron Pollard], Employee [id=1, name=Kieron Pollard]]

Since, set doesn't allow duplicate elements but in the output we are getting duplicates in above scenario. So, what is the correct way to handle this kind of behaviour.

Upvotes: 0

Views: 5713

Answers (2)

Abhijith Nagarajan
Abhijith Nagarajan

Reputation: 4030

Thanks for bringing this up. You should look how the HashSet is implemented. Your example also provides a good idea about why immutability is preferred.

Here is what is happening.

  • You created an object and added it to the HashSet.
  • HashSet stored the reference to the object with the hash of the object. Let us say hash is 10 (For id = 1, name = Chris Gayle)
  • Now, as you change the object, HashSet does not know about the change you made to the object. It holds only the reference but the hash of the object is changed. Let us say it changed to 20 (for id = 1, name = Kieron Pollard).
  • There is a relation between equals and hashcode. If hashcodes of objects are equal then objects could be equal. If the hash codes are different then objects will never be equal. So, by this logic, HashSet added a new entry when you added the same object or the second time.

If you try to create a new HashSet with new HashSet<>(hashSet) then you will see only one object.

Upvotes: 2

rdas
rdas

Reputation: 21285

You shot yourself in the foot here.

@Override
public int hashCode() {
    return Objects.hash(id, name);
}

If hashCode is defined by the id & name & you change the name before adding the object to a HashSet again, you'll obviously get a duplicate entry. Reminder: the uniqueness of an object is determined by the hashCode - and that's what HashSet uses to determine if the object is already in the Set.

What's your uniqueness criterion? If id is meant to be unique, use only id in the hashCode.

@Override
public int hashCode() {
    return Objects.hash(id);
}

Upvotes: 5

Related Questions