Is there any such thing as a combination of Guava's Cache
and Multimap
functionality available? Essentially, I need a collection where entries expire after a given time such as available in Cache
but I have non-unique keys and I need the entries to expire independently.

- 747
- 14
- 26
3 Answers
I think that Louis Wasserman provided the answer in one of the comments above, i.e. that there is no off-the-shelf combo of Multimap
and Cache
available. I have solved my problem/requirements with the solution outlined in pseudo-code below:
private Cache<Integer,Object> cache = CacheBuilder.newBuilder().SomeConfig.build();
private Multimap<Integer,Object> multimap = HashMultimap<Integer, Object>.create();
private AtomicInteger atomicid = new AtomicInteger(0);
public void putInMultimap(int id, Object obj) {
int mapid = atomicid.addAndGet(1);
cache.put(mapid,obj);
multimap.put(id,mapid);
}
public List<Object> getFromMultimap(int id) {
Set<Integer> mapids = multimap.get(id);
List<Object> list = new ArrayList<Object>();
for (int i : mapids) {
list.add(cache.getIfPresent(i));
}
return list;
}
This simple 'solution' has some limitations but it works OK for me.

- 747
- 14
- 26
-
1How do you deal with the ever-growing multimap? – neu242 May 26 '14 at 13:17
-
1@neu242 for the `SomeConfig` part in the current answer you can add a `.removalListener` call there, which will be called whenever something is evicted from the cache, so that you can also remove it from the multimap – Philipp Gayret Jun 03 '14 at 22:10
With a Guava Cache there is no put method, the cache is designed to be self-populating. The values returned from a key lookup are calculated at runtime. A similar approach is taken by Commons Collections Transformer Factories.
I think you could implement what you are looking for quite easily. If you look at a simple Map backed example such as Kitty-Cache you can see that you could replace the Map with a Multimap and rewrite the other methods accordingly. So in KittyCache.java internally you could have something like:
Multimap<K, CacheEntry<V>> cache;
The trick for this kind of cache is that nothing really expires until someone requests it.

- 11,470
- 2
- 48
- 79
-
3"With a Guava Cache there is no put method, the cache is designed to be self-populating" -- this isn't true. It is true `Cache` itself has no method "put" and that `LoadingCache` is designed to be self-populating, but you can always use a non-loading cache, and call `cache.asMap().put(...)` to add your own entries. Of course, this doesn't get you a multimap. Just correcting that first statement. – Ray Mar 05 '12 at 13:18
-
2Since Guava 11.0 there is a [put method](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/cache/Cache.html#put(K, V)) in `Cache`. The example you provided is interesting but I cannot rely on expiration on requests, I implement `RemovalListener`'s to get notification on expirations in the `Cache`. – hgus1294 Mar 05 '12 at 13:26
-
1Thanks for putting this straight Ray. I was quoting: http://java.dzone.com/articles/google-guava-cache – Mark McLaren Mar 05 '12 at 13:50
-
-
Mark, I believe that article was published shortly before 11.0 was released, hence the confusion. – Ray Mar 05 '12 at 14:35
-
For info: "Caches built with CacheBuilder do not perform cleanup and evict values "automatically," or instantly after a value expires, or anything of the sort. Instead, it performs small amounts of maintenance during write operations, or during occasional read operations if writes are rare." See: http://code.google.com/p/guava-libraries/wiki/CachesExplained#Removal_Listeners – Mark McLaren Mar 05 '12 at 15:21
-
3All this said, `Multimap` implementations are extremely nontrivial, and our internal implementations aren't designed to handle cache entries expiring. This would be a pretty major project. =/ – Louis Wasserman Mar 05 '12 at 16:13
-
@LouisWasserman 'Major project', so not before end of month? Just kidding, I appreciate the feedback Louis. Thanks – hgus1294 Mar 05 '12 at 16:25
-
...It _could_ be a month-long project to get something that manages to correctly satisfy the `Multimap` contract. Seriously. – Louis Wasserman Mar 05 '12 at 21:42
As long as you're talking about Cache
and not LoadingCache
you could pass the Cache.asMap()
view into Multimaps.newMultimap
.

- 581
- 2
- 5
-
Interesting. I did some testing but I cannot get the entries to expire independently. I passed a `Cache.asMap()` into a `Multimaps.newMultimap` according to your suggestion and did some quick testing with with `expireAfterWrite` set to 1000 ms and ran the following scenario: `map.put(1,Object1);` `Thread.Sleep(700)` `map.put(1,Object2);` `Thread.Sleep(500)`. At this point I expect the first entry to be evicted but the second to remain but I find both entries to be evicted. Maybe I am doing something wrong but unless I can change the behavior, it does not work for me. – hgus1294 Mar 09 '12 at 14:51