I have similar problem to one discussed here, but with stronger practical usage.
For example, I have a Map<String, Integer>, and I have some function, which is given a key and in case the mapped integer value is negative, puts NULL to the map:
Map<String, Integer> map = new HashMap<String, Integer>();
public void nullifyIfNegative(String key) {
Integer value = map.get(key);
if (value != null && value.intValue() < 0) {
map.put(key, null);
}
}
I this case, the lookup (and hence, hashCode calculation for the key) is done twice: one for lookup and one for replacement. It would be nice to have another method (which is already in HashMap) and allows to make this more effective:
public void nullifyIfNegative(String key) {
Map.Entry<String, Integer> entry = map.getEntry(key);
if (entry != null && entry.getValue().intValue() < 0) {
entry.setValue(null);
}
}
The same concerns cases, when you want to manipulate immutable objects, which can be map values:
Map<String, String>: I want to append something to the string value.Map<String, int[]>: I want to insert a number into the array.
So the case is quite common. Solutions, which might work, but not for me:
- Reflection. Is good, but I cannot sacrifice performance just for this nice feature.
- Use
org.apache.commons.collections.map.AbstractHashedMap(it has at leastprotected getEntry()method), but unfortunately, commons-collections do not support generics. - Use generic commons-collections, but this library (AFAIK) is out-of-date (not in sync with latest library version from Apache), and (what is critical) is not available in central maven repository.
- Use value wrappers, which means "making values mutable" (e.g. use mutable integers [e.g.
org.apache.commons.lang.mutable.MutableInt], or collections instead of arrays). This solutions leads to memory loss, which I would like to avoid. - Try to extend
java.util.HashMapwith custom class implementation (which should be injava.utilpackage) and put it to endorsed folder (asjava.lang.ClassLoaderwill refuse to load it inClass<?> defineClass(String name, byte[] b, int off, int len), see sources), but I don’t want to patch JDK and it seems like the list of packages that can be endorsed, does not includejava.util.
The similar question is already raised on sun.com bugtracker, but I would like to know, what is the opinion of the community and what can be the way out taking in mind the maximum memory & performance effectiveness.
If you agree, this is nice and beneficiary functionality, please, vote this bug!
Not pretty, but you could use lightweight object to hold a reference to the actual value to avoid second lookups.
I wouldn’t worry about hash lookup performance too much though (Steve B’s answer is pretty good in pointing out why). Especially with String keys, I wouldn’t worry too much about
hashCode()as its result is cached. You could worry aboutequals()though as it might be called more than once per lookup. But for short strings (which are often used as keys) this is negligible too.