10

Java 8: Преобразование List<V> в Map<K, V>

11

Я хочу преобразовать список объектов в карту, используя стримы и ламбды в Java 8.

Вот как я бы это сделал в Java 7 и ниже:

private Map<String, Choice> nameMap(List<Choice> choices) {
    final Map<String, Choice> hashMap = new HashMap<>();
    for (final Choice choice : choices) {
        hashMap.put(choice.getName(), choice);
    }
 
    return hashMap;
}

Я могу легко достичь этого, используя Java 8 и библиотеку Guava, но мне хотелось бы узнать, как сделать это без Guava.

Используя Guava:

private Map<String, Choice> nameMap(List<Choice> choices) {
    return Maps.uniqueIndex(choices, new Function<Choice, String>() {

        @Override
        public String apply(final Choice input) {
            return input.getName();
        }

    });
}

А вот вариант с Guava и ламбда-выражениями в Java 8:

private Map<String, Choice> nameMap(List<Choice> choices) {
    return Maps.uniqueIndex(choices, Choice::getName);
}

Как можно реализовать такую функциональность в Java 8 без использования Guava?

5 ответ(ов)

3

Если ваш ключ НЕ гарантированно уникален для всех элементов в списке, вам следует преобразовать его в Map<String, List<Choice>>, а не в Map<String, Choice>. Это позволит вам сохранить все элементы с одинаковым ключом в виде списка.

Пример кода для преобразования будет выглядеть так:

Map<String, List<Choice>> result =
    choices.stream().collect(Collectors.groupingBy(Choice::getName));

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

1

Чтобы использовать метод getName() в качестве ключа и сам объект Choice в качестве значения карты, вы можете воспользоваться следующим кодом на Java:

Map<String, Choice> result =
    choices.stream().collect(Collectors.toMap(Choice::getName, c -> c));

Здесь choices — это коллекция объектов Choice. Мы применяем метод stream(), чтобы создать поток, а затем используем collect вместе с Collectors.toMap(), чтобы собрать результаты в карту. В качестве ключа используется getName(), который возвращает имя выбора, а в качестве значения — сам объект Choice. Это позволяет эффективно создать отображение, где каждому имени соответствует объект выбора.

0

На большинстве ответов не учтён случай, когда в списке есть дублирующиеся элементы. В таком случае ваши ответы могут вызывать IllegalStateException. Вот исправленный код, который обрабатывает дубликаты в списке:

public Map<String, Choice> convertListToMap(List<Choice> choices) {
    return choices.stream()
        .collect(Collectors.toMap(Choice::getName, choice -> choice,
            (oldValue, newValue) -> newValue));
}

В этом коде используется метод Collectors.toMap, который принимает три аргумента: функцию для извлечения ключа, функцию для извлечения значения, а также функцию "слияния" в случае, если для одного ключа встречается несколько элементов. В данном случае, если ключи совпадают, будет использоваться значение последнего элемента.

0

Если вы ищете альтернативу использованию Collectors.toMap(), вот еще один способ сделать это с помощью метода collect():

Map<String, Choice> result =
   choices.stream().collect(HashMap<String, Choice>::new, 
                           (m, c) -> m.put(c.getName(), c),
                           (m, u) -> {});

В этом примере мы создаем новый HashMap при помощи ссылки на конструктор HashMap<String, Choice>::new. Затем мы используем лямбда-выражение (m, c) -> m.put(c.getName(), c) для добавления элементов в карту, где ключом будет имя выбора (c.getName()), а значением – сам объект Choice. Третий аргумент (m, u) -> {} представлен как пустая операция слияния, так как в данном контексте слияние не требуется.

Это позволяет вам гибко управлять тем, как именно вы собираете данные в карту, не полагаясь на предустановленные методы в Collectors.

0

Вот еще один простой вариант:

Map<String, Choice> map = new HashMap<>();
choices.forEach(e -> map.put(e.getName(), e));

В этом коде мы создаем новую HashMap, а затем используем метод forEach, чтобы пройтись по всем элементам в списке choices и добавить каждый элемент в карту, используя имя выбора в качестве ключа.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь