Сбор в Guava ListMultiMap с использованием потоков Java 8

Я пытаюсь собрать в ListMultiMap с помощью java 8 без использования операции forEach.

Если бы я написал код в Java 7, это будет примерно так:

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

Я нашел онлайн веб-сайт, в котором говорится о создании ваших собственных коллекционеров для использования в таких сценариях, как этот. Я использовал эту реализацию для коллекционера. Затем я написал следующий код:

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

Но на уровне сбора я могу передать только один параметр, и я могу найти способ передать два параметра. Следуя примеру веб-сайта, я понял, что для использования обоих я должен хранить "пару" в мультимаре, например следующее:

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

Однако это не то, что я ищу, я хочу собирать в ListMultimap, используя имя штата и название города, используя сборщик java 8 (и no forEach).

Может кто-нибудь мне помочь? Спасибо!

Ответ 2

Вы можете создать для этого пользовательский коллекционер (обратите внимание, что ответ Луи Вассермана будет выполнять внутреннюю проверку forEachOder), вы не сможете избежать выхода изнутри внутри или снаружи).

 ListMultimap<String, String> list = states.collect(Collector.of(ArrayListMultimap::create, (multimap, s) -> {
        multimap.putAll(s.getName(), s.getCities().stream().map(City::getName).collect(Collectors.toList()));
    }, (multi1, multi2) -> {
        multi1.putAll(multi2);
        return multi1;
    }));