Skip to content

Interner

Ben Manes edited this page Apr 28, 2022 · 6 revisions
Interner<String> interner = Interner.newStrongInterner();
String s1 = interner.intern(new String("value"));
String s2 = interner.intern(new String("value"));
assert s1 == s2

An Interner returns a canonical representation of the given element. When the intern(e) method is invoked, if the interner already contains an equal instance, as determined by the Object.equals method, then the instance from the interner is returned. Otherwise, this object is added and that instance is returned. This deduplication is typically used to reduce memory usage by sharing a canonical instance.

LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
    .weakKeys()
    .build(key -> createExpensiveGraph(key));
Interner<Key> interner = Interner.newWeakInterner();

Key canonical = interner.intern(key);
Graph graph = graphs.get(canonical);

A weak interner allows for the interned objects to be garbage collected after there are no more strong references to it. This differs from Caffeine.weakKeys() which uses identity equality (==) to compare keys, instead of equals(). These can be combined by caching the value by the interned key and ensuring that the application retains a strong reference to that canonical key instance. Otherwise, if the cache supported reference equality on weak keys, then the application would most likely hold onto different key instances than that used by the mapping and allow the garbage collector to prematurely evict the cached entry.