Java 8 Преобразование потока набора в карту - PullRequest
0 голосов
/ 10 апреля 2020

Я написал эту лямбду, которая получает значения из карты <Code, Message>, содержащейся в перечислении MessageKeyRegistry, и создает добавление к другой карте с кодом в качестве ключа и MessageKeyRegistry в качестве значения.

Map<MessageKey, MessageKeyRegistry> keyMap = new HashMap<>();
    EnumSet.allOf(MessageKeyRegistry.class)
            .forEach(messageKeyRegistry -> messageKeyRegistry.getCodeToMessage().keySet()
                    .forEach(code -> keyMap.put(code, messageKeyRegistry)));

Теперь я хочу удовлетворить концепцию неизменяемости функционального программирования и написать лямбду, которая напрямую возвращает неизменяемую карту.

Ответы [ 3 ]

2 голосов
/ 10 апреля 2020

Я написал эту лямбду, которая ..

Вы написали не просто лямбду, а цепочку методов с использованием лямбда-выражений. один, если они code -> keyMap.put(code, messageKeyRegistry).

Вернуться к вашему вопросу. Вы начинаете с итерации правильно (с EnumSet), следующий шаг - понять, что происходит в методах forEach.

  • Извлечение кодов из набора ключей с использованием их в качестве ключей с использованием messageKeyRegistry
  • Использование экстрактора в качестве значения messageKeyRegistry.

Это это работа для map, однако, поскольку структура данных более сложна (сбор в коллекцию), тогда flatMap будет работать лучше. Наконец, вы получите что-то вроде:

Map<MessageKey, MessageKeyRegistry> keyMap = EnumSet.allOf(MessageKeyRegistry.class)
        .stream()
        .flatMap(messageKeyRegistry -> messageKeyRegistry.getCodeToMessage().keySet()
             .stream()
             .map(code -> new AbstractMap.SimpleEntry<>(code, messageKeyRegistry)))
        .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

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

.forEach(code -> keyMap.put(code, messageKeyRegistry))

Итак, я предлагаю скорее групповое сопоставление с использованием Collectors.groupingBy, в результате чего Map<MessageKey, List<MessageKeyRegistry>>:

Map<MessageKey, List<MessageKeyRegistry>> keyMap = EnumSet.allOf(MessageKeyRegistry.class)
        .stream()
        .flatMap(messageKeyRegistry -> messageKeyRegistry.getCodeToMessage().keySet()
            .stream()
            .map(code -> new AbstractMap.SimpleEntry<>(code, messageKeyRegistry)))
        .collect(Collectors.groupingBy(Entry::getKey));

Для неизменяемой карты, если вы имеете в виду карту только для чтения, используйте оболочку Collections.unmodifiableMap():

Map<MessageKey, List<MessageKeyRegistry>> unmodifiableKeyMap = Collections.unmodifiableMap(keyMap);
0 голосов
/ 10 апреля 2020

Не самый хороший, но что-то вроде этого должно быть:

Map<MessageKey, MessageKeyRegistry> keyMap = EnumSet.allOf(MessageKeyRegistry.class)
       .stream()
       .flatMap(messageKeyRegistry -> messageKeyRegistry.getCodeToMessage().keySet().stream().map(code -> new Pair(code, messageKeyRegistry))
       .collect(Collectors.toMap(Pair::getKey, Pair::getValue)));
0 голосов
/ 10 апреля 2020

Я не уверен, что концепция неизменяемости функционального программирования, применяемая к java потокам, означает неизменяемые возвращаемые коллекции. Давайте рассмотрим более простой случай

final List<String> result = Stream.of("1", "2").collect(Collectors.toList());
result.add("3");
System.out.println(result);
System.out.println(result.getClass());

, который выводит

[1, 2, 3]
class java.util.ArrayList
...