La-comadreja
La-comadreja

Reputation: 5755

Checking for and Removing elements in Java HashMap

I am trying to check for and remove elements, using a HashMap in Java. Its keys are a type I created called ClusterKey, and its values are a type I created called ClusterValue.

Here is the code that is causing issues:

ClusterKey ck = new ClusterKey(Long.parseLong(split[0].split("=")[1]), 
                        Integer.parseInt(split[1].split("ey")[1]));
if (arg == 0) keys.put(ck, new ClusterValue(index, false));
if (arg == 1) {
    if (keys.containsKey(ck)) {
        index = keys.get(ck).messageNo;
        keys.remove(ck);
    }
    keys.put(ck, new ClusterValue(index, true));
}

The problem is that even when the ClusterKey is the same as an existing ClusterKey, containsKey() and remove() do not seem to recognize it as equal. I have implemented equals() in class ClusterKey to override Java's equals() method, as follows:

class ClusterKey {
    long firstKey;
    int secondKey;
    public ClusterKey(long firstKey, int secondKey) {
        this.firstKey = firstKey;
        this.secondKey = secondKey;
    } public boolean equals(Object otherKey) {
        return this.firstKey == ((ClusterKey) otherKey).firstKey && this.secondKey == ((ClusterKey) otherKey).secondKey;
    }
}

So, I'm quite confused. Thanks so much for your help.

Regards, Rebecca

UPDATE: Thank you for your advice and feedback on my code. I was able to solve the problem by adding hashCode() to ClusterKey, as follows:

    } public boolean equals(Object otherKey) {
        return this.firstKey == ((ClusterKey) otherKey).firstKey && this.secondKey == ((ClusterKey) otherKey).secondKey;
    } public int hashCode() {
        return (int) firstKey + secondKey;
    } 

Upvotes: 2

Views: 2063

Answers (2)

Ravi K Thapliyal
Ravi K Thapliyal

Reputation: 51711

For any Hash enabled data structure (like HashMap, HashSet) to work correctly its elements must override hashCode() in addition to the equals() method. The reason being that the hash code is used to identify the bucket in which to put the element (during insertion) or search in (using equals() during a lookup).

If you do not override hashCode(), the default implementation from Object#hashCode() is used which would return different values even for the objects that you consider equivalent (the equals() method returns true for).

This is why your

 hashMap.containsKey(ClusterKey key)

calls are failing in spite of the key already being present. Since, the hash codes don't match the HashMap never looks for the key in the right bucket. Hence, your equals() never gets called here.

Upvotes: 3

rgettman
rgettman

Reputation: 178263

You will need to implement hashCode(), not just equals, for your ClusterKey to work well as a key in a HashMap.

Specifically, quoting from the linked Javadocs:

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

Upvotes: 3

Related Questions