0

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.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
user3244519
  • 661
  • 5
  • 18
  • 36
  • Why the [tag:java-ee] tag? What does your question have to do *directly* with Java Enterprise Edition server-client interoptions? – Hovercraft Full Of Eels Apr 19 '19 at 11:47
  • I've [edit]ed your question and updated tags. Please be careful with tags as they and your question title are the most important parts of your question, the ones that help draw the right experts to review it – Hovercraft Full Of Eels Apr 19 '19 at 11:49

2 Answers2

5

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);
}
rdas
  • 20,604
  • 6
  • 33
  • 46
2

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 a object 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 hash of the object is changed. Let us say 20 (for id = 1, name = Kieron Pollard).
  • There is a relation between equals and dashcode. If hash codes of objects are equal then objects could be equal. 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.

Abhijith Nagarajan
  • 3,865
  • 18
  • 23