Is there any way how to get the key (or the whole entry) from a HashMap (or another suitable Map) efficiently?
Before somebody says, I never need it: I do. I have a loop like this
for (long i=0; i<1e12; ++i) {
Key key = new Key(i);
Value value = map.get(key);
if (something(key, value)) list.add(key);
}
and my key needlessly takes memory which could be saved if I could replace list.add(key) by something like list.add(map.getKey(key)) (the new instance would be eligible for GC). While they’re equal, reusing the old instance would save memory.
I know I can embed the key into the value or use Guava’s Interner; both helps, but both also costs some memory.
To address some misunderstanding comments: If efficiency was no issue, the following would do
Key getKeyFromMap(Key key, Map<Key, ?> map) {
for (Key key2 : map.keySet()) {
if (key.equals(key2)) return key2;
}
return null;
}
The most efficient solution as described in the accepted answer:
public static <K, V> K getKey(K key, HashMap<K, V> map) {
final Entry<K, V> entry = map.getEntry(key);
return entry==null ? null : entry.getKey();
}
The problem is that it must be placed into package java.util as it uses a package private method. It can be dangerous to use such a method, but it’s no problem in my “run-once” use case.
How much evil are you prepared to commit in order to do this?
The
Mapinterface does not let you retrieve a key or an entry. Nor does theSetinterface. Nor doesHashMap‘s public interface.But
HashMap‘s package interface does (in the Sun JDK, at least). Have a look at the source code; at line 355, there is a method calledgetEntrywhich starts like this:I believe that is exactly what you need. You can call this with reflection, or by sneaking a class of your own into the
java.utilpackage. The Java maintainers could take this method away in the future, and it might not be present on all platforms, but if you’re prepared to hold your nose and take the risk, it’s a simple solution.