1

I want to use a WeakHashMap for objects that will exist in memory for a short time.

Each object has an id (unique integer field which is a primary key from DB), so my 1st thought was to use that field as the key for the object.

However, Integer is immutable, so AFAIK, the hash will produce another immutable Integer and thus the object will not be GCed as long as any other non related object points to it.

Is there a way to use an Integer key in a WeakHashMap?

Maroun
  • 94,125
  • 30
  • 188
  • 241
Lior Tamir
  • 53
  • 4
  • 1
    I don’t quite understand the question, but if it is a problem with the immutability of a `java.lang.Integer`, you could potentially create your own wrapped int object. – vandench Jul 23 '18 at 11:41
  • 1
    How about using an in-memory Cache implementation with appropriate expiration policy (maximum size or cache age)? – Thilo Jul 23 '18 at 11:42
  • I don't think your concern is valid. Each `new Integer(...)` call produces a new instance of an Integer. It won't reuse any existing instances - this does not have anything to do with the immuability of Integer objects. There's an exception to that though: Integer instances in range of -128 .. 127, if they are created by autoboxing (rather than a new instance) are by default cached. See e.g. https://stackoverflow.com/questions/3130311/weird-integer-boxing-in-java . Populating the map with `map.put(new Integer(myId), ...)` should be imo safe. – david a. Jul 23 '18 at 11:44

3 Answers3

3

Using an Integer key in a WeakHashMap doesn't prevent keys from being removed. An Integer key may be garbage collected once no references exist to the same Integer instance that was put into the Map. If there exist references to different Integer instances equal (i.e. having the same numeric value) to a key in the WeakHashMap, that doesn't prevent the key from being automatically removed.

Note that the value of your WeakHashMap must not hold a strong reference to the key - otherwise the key can never be automatically removed. So to avoid that, simply add values to the WeakHashMap as follows:

Integer key = new Integer(someObject.getID());
weakMap.put(key,someObject);

Now, once you no longer keep a reference to the Integer instance referenced by the key variable, the WeakHashMap will be free to automatically remove it.

If you put the entry in the WeakHashMap without keeping a reference to the key (i.e. weakMap.put(new Integer(someObject.getID()),someObject)), the WeakHashMap will be able to auto-remove it immediately, which I don't think is what you wanted.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • 1
    Note that in this case the key can be garbage collected while someObject is still used somewhere. – WilQu Jul 23 '18 at 12:00
  • @WilQu did you write that comment before I edited my answer? I just addressed this before noticing the comment. – Eran Jul 23 '18 at 12:01
  • Yes but it’s still valid. Not only do you have to keep a reference to key, but you have to keep as long as you keep someObject. – WilQu Jul 23 '18 at 12:04
  • @WilQu you need to keep a reference to the key as long as you don't want the key to be auto-removed. That's what I meant. – Eran Jul 23 '18 at 12:13
  • BTW, `new Integer(int)` deprecated for removal. – Jin Kwon Apr 21 '23 at 02:33
1

As you said, the WeakHashMap will not provide the desired functionality. The JavaDocs state the following

Thus care should be taken to ensure that value objects do not strongly refer to their own keys, either directly or indirectly, since that will prevent the keys from being discarded.

So you might implement a "WeakValueMap". But this is not as complicated as it sounds. Either you simply wrap the WeakReference in the type definition

Map<Integer, WeakReference<YourType>> cache ...

Or you implement a wrapper implementation around it.

public class Cache<K, V> implements Map<K, V> {
   private final Map<K, V> store = new HashMap<>();

  // implement put, get, etc.
}
M.F
  • 403
  • 2
  • 10
0

One of the issues with using Integer as a key in a WeakHashMap is that the Integer can be garbage collected while the value it maps to is still used in memory.

If what you want is to have the items as values in a HashMap whithout preventing them from being garbage collected, then you should wrap them into a WeakReference and use them as a value in a regular map Map<Integer, <WeakReference<Item>>, maybe with a mechanism to remove unused keys from time to time.

Or, if being able to retrieve them from their ids is not a requirement, you can use the Items themselves as a key to a WeakHashMap, and create a set from them using Collections#newSetFromMap

WilQu
  • 7,131
  • 6
  • 30
  • 38