Java HashMap containsKey returns false for existing object

containskey, hashmap, java

Solution

You shall not modify the key after having inserted it in the map.

Edit : I found the extract of javadoc in Map :

Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.

Example with a simple wrapper class:

public static class MyWrapper {

  private int i;

  public MyWrapper(int i) {
    this.i = i;
  }

  public void setI(int i) {
    this.i = i;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    return i == ((MyWrapper) o).i;
  }

  @Override
  public int hashCode() {
    return i;
  }
}

and the test :

public static void main(String[] args) throws Exception {
  Map<MyWrapper, String> map = new HashMap<MyWrapper, String>();
  MyWrapper wrapper = new MyWrapper(1);
  map.put(wrapper, "hello");
  System.out.println(map.containsKey(wrapper));
  wrapper.setI(2);
  System.out.println(map.containsKey(wrapper));
}

Output :

true
false

Note : If you dont override hashcode() then you will get true only

Problem

I have a HashMap for storing objects: ``` private Map<T, U> fields = Collections.synchronizedMap(new HashMap<T, U>()); ``` but, when trying to check existence of a key, `containsKey` method returns `false`. `equals` and `hashCode` methods are implemented, but the key is not found. When debugging a piece of code: ``` return fields.containsKey(bean) && fields.get(bean).isChecked(); ``` I have: ``` bean.hashCode() = 1979946475 fields.keySet().iterator().next().hashCode() = 1979946475 bean.equals(fields.keySet().iterator().next())= true fields.keySet().iterator().next().equals(bean) = true ``` but ``` fields.containsKey(bean) = false ``` What could cause such strange behavioure? ``` public class Address extends DtoImpl<Long, Long> implements Serializable{ <fields> <getters and setters> @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + StringUtils.trimToEmpty(street).hashCode(); result = prime * result + StringUtils.trimToEmpty(town).hashCode(); result = prime * result + StringUtils.trimToEmpty(code).hashCode(); result = prime * result + ((country == null) ? 0 : country.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Address other = (Address) obj; if (!StringUtils.trimToEmpty(street).equals(StringUtils.trimToEmpty(other.getStreet()))) return false; if (!StringUtils.trimToEmpty(town).equals(StringUtils.trimToEmpty(other.getTown()))) return false; if (!StringUtils.trimToEmpty(code).equals(StringUtils.trimToEmpty(other.getCode()))) return false; if (country == null) { if (other.country != null) return false; } else if (!country.equals(other.country)) return false; return true; } } ```

Original source