Collect into Guava's ListMultiMap using Java 8 streams

codastic picture codastic · Feb 14, 2017 · Viewed 8k times · Source

I am trying to collect into a ListMultiMap using java 8 without using the forEach operation.

If I were to write the code in Java 7, it will be something like this:

ListMultimap<String, String> result = ArrayListMultimap.create();
     for(State state: states) {
      for(City city: state.getCities()) {
        result.put(state.getName(), city.getName());
      }
    }

I found online a website that talks about creating your own collectors to use in scenarios such as this one. I used this implementation for the collector. I then wrote the following code:

     ListMultimap<String, String> result = states
        .stream()
        .flatMap(state -> state.getCities().stream()
            .map(city -> {
              return new Pair(state, city);
            }))
        .map(pair -> {
          return new Pair(pair.first().getName(), pair.second().getName()));
        })
        .collect(MultiMapCollectors.listMultimap(
                    Pair::first,
                    Pair::second
                )
        );

But at the collect level, I can only pass just one parameter, and I can seem to find a way to pass two parameters. Following the example from the website, I understood that to use both, I need to store a "pair" in the multimap such as the following:

ArrayListMultimap<String, Pair> testMap = testObjectList.stream().collect(MultiMapCollectors.listMultimap((Pair p) -> p.first().getName()));

However this is not what I'm looking for, I want to collect into ListMultimap using the state's name and the city's name using java 8's collector (and no forEach).

Can someone help me with that ? Thank you!

Answer

Louis Wasserman picture Louis Wasserman · Feb 14, 2017

ImmutableListMultimap.flatteningToImmutableListMultimap

return states.stream()
   .collect(flatteningToImmutableListMultimap(
      State::getName,
      state -> state.getCities().stream().map(City::getName)));