It’s not uncommon in Java to build some sort of in-memory registry that contains a map with a list of items at each position. Often, these implementations look something like this (excluding concurrency details for brevity):
1private Map<String,List<Something>> stuff = new HashMap<String,List<Something>>();
2
3// ...
4
5public void add(String key, Something item) {
6 if(!stuff.containsKey(key)) {
7 stuff.put(key, new ArrayList<Something>());
8 }
9 stuff.get(key).add(item);
10}
11
12public List<Something> get(String key) {
13 return new ArrayList<Something>(stuff.get(key));
14}
Google’s Guava Libraries provide a few collections to help with this common case: com.google.common.collect.Multimap
, and the more specific variants ListMultimap
, SetMultimap
, and SortedSetMultimap
.
The above code can be re-written with Guava like this:
1private ListMultimap<String,Something> stuff = ArrayListMultimap.create();
2
3// ...
4
5public void add(String key, Something item) {
6 stuff.put(key, item);
7}
8
9public List<Something> get(String key) {
10 // might as well use the Lists convenience API while we're at it.
11 return Lists.newArrayList(stuff.get(key));
12}
The multi-map has a variety of fancy features that can be used as well. Here are just a few examples:
1// returns a composite of all values from all entries.
2Collection<Something> allSomethings = stuff.values();
3
4// A more traditional map that can be edited.
5Map<String, Collection<Something>> mapView = stuff.asMap();
6
7// remove an individual entry for a key.
8boolean removed = stuff.remove(key, someVal);
9
10// remove all for a key
11List<Something> removedSomethings = stuff.remove(key);
12
13// One for each value in the map. Updating this collection updates the map.
14Collection<Map.Entry<String,Something>> allEntries = stuff.entries();
All of the collections returned by the various API are views of the multimap. This can make it particularly easy to work with the map in a variety of ways. It does mean you should probably perform defensive copying anywhere you might be exposing these APIs (generally good practice in most cases, anyway).