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; } } ```