Java 8: Преобразование List<V> в Map<K, V>
Я хочу преобразовать список объектов в карту, используя стримы и ламбды в 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 ответ(ов)
Если ваш ключ НЕ гарантированно уникален для всех элементов в списке, вам следует преобразовать его в Map<String, List<Choice>>
, а не в Map<String, Choice>
. Это позволит вам сохранить все элементы с одинаковым ключом в виде списка.
Пример кода для преобразования будет выглядеть так:
Map<String, List<Choice>> result =
choices.stream().collect(Collectors.groupingBy(Choice::getName));
Таким образом, если у вас несколько элементов с одинаковым именем, они будут сгруппированы в список, что обеспечит корректное хранение всех значений, связанных с одним ключом.
Чтобы использовать метод getName()
в качестве ключа и сам объект Choice
в качестве значения карты, вы можете воспользоваться следующим кодом на Java:
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(Choice::getName, c -> c));
Здесь choices
— это коллекция объектов Choice
. Мы применяем метод stream()
, чтобы создать поток, а затем используем collect
вместе с Collectors.toMap()
, чтобы собрать результаты в карту. В качестве ключа используется getName()
, который возвращает имя выбора, а в качестве значения — сам объект Choice
. Это позволяет эффективно создать отображение, где каждому имени соответствует объект выбора.
На большинстве ответов не учтён случай, когда в списке есть дублирующиеся элементы. В таком случае ваши ответы могут вызывать IllegalStateException
. Вот исправленный код, который обрабатывает дубликаты в списке:
public Map<String, Choice> convertListToMap(List<Choice> choices) {
return choices.stream()
.collect(Collectors.toMap(Choice::getName, choice -> choice,
(oldValue, newValue) -> newValue));
}
В этом коде используется метод Collectors.toMap
, который принимает три аргумента: функцию для извлечения ключа, функцию для извлечения значения, а также функцию "слияния" в случае, если для одного ключа встречается несколько элементов. В данном случае, если ключи совпадают, будет использоваться значение последнего элемента.
Если вы ищете альтернативу использованию 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.
Вот еще один простой вариант:
Map<String, Choice> map = new HashMap<>();
choices.forEach(e -> map.put(e.getName(), e));
В этом коде мы создаем новую HashMap
, а затем используем метод forEach
, чтобы пройтись по всем элементам в списке choices
и добавить каждый элемент в карту, используя имя выбора в качестве ключа.
Как определить, содержится ли определенное значение в массиве в Java?
Сортировка ArrayList пользовательских объектов по свойству
Как установить Java 8 на Mac
Оператор двойного двоеточия (::) в Java 8
Что такое PECS (Producer Extends Consumer Super)?