6

We have a Scala server that is getting a node tree using Protocol Buffers over a socket and we need to attach additional data to each node.

In a single threaded context and when both the node tree and the associated data will have their strong references removed at the same time (due to going out of scope), is there any reason to use Google Guava's MapMaker with weakKeys() over using WeakHashMap? It seems that with MapMaker, one pays for synchronized access, which isn't needed in this case.

As an aside, it would be useful if MapMaker were to give access to the equivalence settings so one could choose reference equality but not care about weak or soft references.

javamonkey79
  • 17,443
  • 36
  • 114
  • 172
Blair Zajac
  • 4,555
  • 3
  • 25
  • 36

1 Answers1

6

One significant downside to WeakHashMap is that it is not an "identity map". That is, it uses equals() and hashCode (rather than == and identityHashCode) on keys, which really doesn't make sense for weak keys. You can work around this bug by making sure that your keys use identity equality in their equals method.

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
  • Thanks Laurence, I quickly scanned the Javadoc and assumed it would be implemented using == and identityHashCode, but doing a closer reading matches your description. – Blair Zajac Nov 20 '10 at 20:54
  • Also, one could still use java.util.HashMap and write a custom ReferenceEquivalence that contains a single T and uses == and identityHashCode? – Blair Zajac Nov 20 '10 at 20:56
  • You could, but you'll need something to purge dead keys from the `HashMap`. As an aside, I haven't verified this by looking at the code, but I wonder if the removal of dead keys/values is part of the reason `MapMaker` uses a `ConcurrentMap`. – Laurence Gonsalves Nov 20 '10 at 23:06
  • @LaurenceGonsalves Why using `equals()` and `hashCode()` doesn't make sense for weak keys? – FredSuvn Mar 21 '22 at 13:43
  • @FredSuvn Typically you want the value for any key you `put` to survive so long as the key is otherwise reachable. Say `o1.equals(o2)`, but `o1 != o2`. If you put a value for `o1` and also for `o2` in the map (even if you merge the values somehow) only one of these keys will be there afterwards. Lets say `o1` is the one that remains. Now we can look up either `o1` or `o2` and get our value. Fine, until later if `o1` becomes unreachable, but `o2` is still reachable. Because the map had a weak ref to `o1`, the mapping may get deleted, and if we look up `o2`, we won't find anything. – Laurence Gonsalves Mar 22 '22 at 16:14
  • @LaurenceGonsalves Think about it: let `map` be a HashMap (strong, no weak), `map.put(o1); map.put(o2); map.remove(o1);` Then what should we get from `map.get(o2)`? It is equivalent to `weakMap`: `weakMap.put(o1); weakMap.put(o2);`, and later, the GC collects the `o1` (same effect: `weakMap.remove(o1)`) – FredSuvn Mar 22 '22 at 16:39
  • @FredSuvn the point is that things you don't want removed can get removed. If you only use put and get (not iteration or deletion) on a map with weak keys, it should behave exactly like a regular map, except that values that are no longer reachable (via get) get cleaned up. A weak map with non-identity keys violates that expectation, as the value for a key can get automatically removed before the key has become unreachable. – Laurence Gonsalves Mar 25 '22 at 00:05