Skip to main content

Google Guava and Multimaps

·2 mins

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):

private Map<String,List<Something>> stuff = new HashMap<String,List<Something>>();

// ...

public void add(String key, Something item) {
  if(!stuff.containsKey(key)) {
    stuff.put(key, new ArrayList<Something>());
  }
  stuff.get(key).add(item);
}

public List<Something> get(String key) {
  return new ArrayList<Something>(stuff.get(key));
}

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:

private ListMultimap<String,Something> stuff = ArrayListMultimap.create();

// ...

public void add(String key, Something item) {
  stuff.put(key, item);
}

public List<Something> get(String key) {
  // might as well use the Lists convenience API while we're at it.
  return Lists.newArrayList(stuff.get(key));
}

The multi-map has a variety of fancy features that can be used as well. Here are just a few examples:

// returns a composite of all values from all entries.
Collection<Something> allSomethings = stuff.values();

// A more traditional map that can be edited.
Map<String, Collection<Something>> mapView = stuff.asMap();

// remove an individual entry for a key.
boolean removed = stuff.remove(key, someVal);

// remove all for a key
List<Something> removedSomethings = stuff.remove(key);

// One for each value in the map. Updating this collection updates the map.
Collection<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).