45

If I want to create a new Multimap with simple defaults, I curently need to do something like:

private final Multimap<Key, Value> providersToClasses = Multimaps
        .newListMultimap(
                new HashMap<Key, Collection<Value>>(),
                new Supplier<List<Value>>() {
                    @Override
                    public List<Value> get() {
                        return Lists.newArrayList();
                    }
                });

...because Java can't infer the correct types if Maps.newHashMap is used for the backing map. Of course, this can be refactored into a separate method, but is there already a way to write it more concisely?

Lii
  • 11,553
  • 8
  • 64
  • 88
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487

6 Answers6

62

Why aren't you using ArrayListMultimap.create() for such a simple case? It's the default way to create the simple HashMap/ArrayList that is probably the most common used multimap.

CubeJockey
  • 2,209
  • 8
  • 24
  • 31
Daniel Teply
  • 1,974
  • 1
  • 13
  • 10
  • 2
    I think you mean `ArrayListMultimap`. `HashMultimap` is for `HashMap`/`HashSet`. – Louis Wasserman May 17 '12 at 15:13
  • 14
    We were concerned about this, so we put this doc on newListMultimap(): "Call this method only when the simpler methods ArrayListMultimap.create() and LinkedListMultimap.create() won't suffice." – Kevin Bourrillion May 17 '12 at 18:03
  • Hi, @KevinBourrillion. Forcing that factory parameter creates lots of noise for sometimes very simple usecases. What would be very useful to have simplified version, something like that NewListMultimap(Map> map) which would create multiMaps using some default factory. I have lot's MultivaluedMap classes from Jersey to convert to multimaps and that conversion code makes it very difficult to read the code. – husayt Dec 27 '12 at 19:51
  • 2
    As of version 21.0, the documentation states that this method will be deprecated, in favor of ```MultimapBuilder.hashKeys().arrayListValues().build()```. – Arve Feb 09 '17 at 10:18
24

I run into this problem when writing clients and building up maps of query params. A nice succinct pattern I like for constructing multi-maps is to use ImmutableMultiMap#builder

Multimap<String, String> queryParams = 
  ImmutableMultimap.<String, String>builder()
    .put("key-1", "value-1")
    .put("key-1", "value-2")
    .build();
Sam Berry
  • 7,394
  • 6
  • 40
  • 58
15

The Guava documentation states that the create method advocated by some other answers "will soon be deprecated" in favour of the different forms presented below, and should therefore be avoided.

From Guava 21.0 onwards, the recommended way of creating a Multimap object where values are stored in ArrayList collections is the following:

MultimapBuilder.hashKeys().arrayListValues().build();

You can also use parameters if you want to specify the expected number of keys in your map and the expected number of values per key:

MultimapBuilder.hashKeys(expectedKeys).arrayListValues(expectedValuesPerKey).build();

Finally, you can create a new Multimap from an existing one using this construct:

MultimapBuilder.hashKeys().arrayListValues().build(multimap);

If you want to use data structures other than ArrayLists in your Multimap, you can replace the call to arrayListValues() by a number of other ones, listed here.

Pyves
  • 6,333
  • 7
  • 41
  • 59
6

Here is compact solution:

Multimap<Integer, String> multi = HashMultimap.create();
4

In Java 8 this is much nicer, for all kinds of multimaps. This is for two reasons:

It looks like this:

Multimap<Key, Value> providersToClasses =
    Multimaps.newListMultimap(new HashMap<>(), ArrayList::new);
Lii
  • 11,553
  • 8
  • 64
  • 88
2

To answer the original type inference problem, though, you can also specify the generic types on a static method using Maps.<Key, Collection<Value>>newHashMap(), but it's certainly not more concise than new HashMap<Key, Collection<Value>>() (it may be more consistent).

Frank Pavageau
  • 11,477
  • 1
  • 43
  • 53