Guava's Multimap

Maps and List are the bread and butter of any Java program, but sometimes you need to creating a map that associates one key to multiple values and end up creating a Map<K, List<V>> or similar. If you’ve ever needed that sort of collection, Guava has you covered with its Multimap.

Guava’s Multimap is designed to represent a map where for one key there is a collection of values. There are two main variants (subinterfaces) of Multimaps: ListMultimap, which acts as if the collection is a List (meaning there can be duplicates associated to the same key) and SetMultimap, which doesn’t allow duplicated pairs.

Using Multimap is much nicer than a Map<K, List<V>>, mostly because you don’t have to handle the case “the value collection is null since there is nothing associated to the key”: Multimap will always return an empty collection and never null. Futhermore, Guava will consider a key present if and only if it is associated to a value, meaning that removing a pair might remove the key from the map if it was associated only to one value. This is quite helpful in a lot of cases.

All the standard API that you would expect are available:

and so on.

Design notes

Quoting directly from the Multimap’s javadoc:

A collection that maps keys to values, similar to Map, but in which each key may be associated with multiple values. You can visualize the contents of a multimap either as a map from keys to nonempty collections of values:

a → 1, 2

b → 3

… or as a single “flattened” collection of key-value pairs:

a → 1

a → 2

b → 3

Important: although the first interpretation resembles how most multimaps are implemented, the design of the Multimap API is based on the second form. So, using the multimap shown above as an example, the size() is 3, not 2, and the values() collection is [1, 2, 3], not [[1, 2], [3]].

Implementations

There are multiple implementations of Multimap available, the most commonly used are:

Views

Multimap supports a powerful concept of views: methods that returns collections that map to the underlying multimap. For instance, you can do things like:

Multimap<String, String> m = HashMultimap.create();
m.get("a").put("b");
assertTrue(m.containsEntry("a", "b"));

The Collection returned by get is modifiable: whenever you make a change to it, the modifications are reflected to the underlying Multimap.

Other useful methods that return a view of the multimap are:

  • asMap which returns a Map<K, Collection<V>>;
  • entries which returns a Collection<Map.Entry<K, V>>;
  • keySet which returns a Set<K>;
  • values which returns a Collection<V>.

Conclusions

Chances are you’ve written in the past a Map<K, Collection<V>>. In almost all cases, Multimap is a better choice and offers a much better API. Go and use it!