- преобразовать список в hashmap в java, используя stream api [duplicate]
- 18 ответов
- Stream to HashMap :
- 1. Using Collectors.toMap(keyMapper, valueMapper, mergeFunction)
- StreamToMapUsingCollectorsToMap.java
- 2. Using Collectors.toMap(keyMapper, valueMapper, mergeFunction, supplier)
- StreamToHashMapUsingCollectorsToMap.java
- Related Articles:
- References :
- Collecting Stream Items into Map in Java
- Java stream collect to hashmap
преобразовать список в hashmap в java, используя stream api [duplicate]
Встроенный div является уродцем сети и amp; должен быть избит до тех пор, пока он не станет промежутком (по крайней мере 9 раз из 10) .
. отвечает на исходный вопрос .
18 ответов
На основе Collectors документации это так же просто, как:
Map result = choices.stream().collect(Collectors.toMap(Choice::getName, Function.identity()));
В качестве примечания, даже после Java 8, JDK по-прежнему не может участвовать в конкурсе на краткость. Альтернатива Guava выглядит настолько читаемой: Maps.uniqueIndex(choices, Choice::getName) . – Bogdan Calmac 3 March 2015 в 18:59
@BogdanCalmac Это довольно тривиально написать такой метод uniqueIndex() самостоятельно в Java 8. – herman 28 August 2016 в 21:37
Есть ли преимущества использования функции. Я имею в виду, это — & gt; он короче – shabunc 30 May 2017 в 12:49
@shabunc Я не знаю никакой пользы и фактически использую it -> it сам. Function.identity() используется здесь главным образом потому, что он используется в ссылочной документации, и это все, что я знал о лямбдах во время написания – zapl 30 May 2017 в 12:57
@zapl, о, на самом деле выясняется, что есть причины этого — stackoverflow.com/questions/28032827/… – shabunc 30 May 2017 в 13:39
Используйте getName () как ключ и сам выбор как значение карты:
Map result = choices.stream().collect(Collectors.toMap(Choice::getName, c -> c));
Пожалуйста, напишите некоторое описание, чтобы пользователь мог понять. – Mayank Jain 28 February 2015 в 08:38
Это очень плохо, здесь нет более подробных сведений, потому что мне нравится этот ответ лучше всего. – MadConan 24 November 2015 в 14:50
Он равен choices.stream().collect(Collectors.toMap(choice -> choice.getName(),choice -> choice)); Первая функция для ключа, вторая функция для значения – waterscar 6 January 2016 в 08:29
Я знаю, как легко видеть и понимать c -> c , но Function.identity() несет большую семантическую информацию. Обычно я использую статический импорт, так что я могу просто использовать identity() – Hank D 9 April 2016 в 21:06
Вот еще один случай, если вы не хотите использовать Collectors.toMap ()
Map result = choices.stream().collect(HashMap::new, (m, c) -> m.put(c.getName(), c), (m, u) -> <>);
Что лучше использовать тогда Collectors.toMap() или наш собственный HashMap, как вы показали в приведенном выше примере? – Swapnil Gangrade 18 July 2016 в 14:22
В этом примере приведен пример того, как разместить на карте что-то еще. Я хотел, чтобы значение не предоставлялось вызовом метода. Благодаря! – th3morg 21 April 2017 в 01:51
Третья функция аргумента неверна. Там вы должны предоставить некоторую функцию для объединения двух Hashmaps, что-то вроде Hashmap :: putAll – jesantana 21 July 2017 в 08:34
Я напишу, как преобразовать список в карту с помощью дженериков и инверсии элемента управления. Просто универсальный метод!
Возможно, у нас есть список целых чисел или список объектов. Итак, вопрос заключается в следующем: что должно быть ключом к карте?
public interface KeyFinder
теперь с помощью инверсии управления:
static Map listToMap(List list, KeyFinder finder) < return list.stream().collect(Collectors.toMap(e ->finder.getKey(e) , e -> e)); >
Например, если у нас есть объекты книги, этот класс должен выбрать ключ для карты
public class BookKeyFinder implements KeyFinder < @Override public Long getKey(Book e) < return e.getPrice() >>
Если вы не против использовать сторонний lib ( Vavr (ранее известный как Javaslang) ), вы можете использовать мощные новые неизменные коллекции:
// import javaslang.collection.*; Map map = list.toMap(choice -> Tuple.of(choice.getName(), choice));
Там также много методов для преобразования Java-коллекций вперед и назад.
Пожалуйста, прочитайте подробнее о новых коллекциях здесь.
Отказ от ответственности: я являюсь создателем Vavr.
Я пытался это сделать и обнаружил, что, используя ответы выше, при использовании Functions.identity() для ключа к карте, у меня возникли проблемы с использованием локального метода, такого как this::localMethodName , чтобы фактически работать из-за ввода вопросов .
Functions.identity() фактически что-то делает для ввода в этом случае, поэтому метод будет работать только путем возврата Object и принятия параметра Object
. Чтобы решить эту проблему, Я закончил тем самым Functions.identity() и использовал s->s .
Итак, мой код, в моем случае, чтобы перечислить все каталоги внутри каталога, и для каждого из них используйте имя каталога как ключ к карту, а затем вызвать метод с именем каталога и вернуть коллекцию элементов, выглядит так:
Map> items = Arrays.stream(itemFilesDir.listFiles(File::isDirectory)) .map(File::getName) .collect(Collectors.toMap(s->s, this::retrieveBrandItems));
Stream to HashMap :
1. Using Collectors.toMap(keyMapper, valueMapper, mergeFunction)
- First variant of Collectors.toMap() method accepts 3 input-arguments
- Key mapper – mapping function to produce keys
- Value mapper – mapping function to produce values
- Merge Function – this is used to resolve collisions between values associated with the same key
- Above method helps to convert Stream into Map
- For converting into HashMap, create HashMap object and pass above obtained Map as constructor-argument
- Finally, print converted HashMap pairs to console
StreamToMapUsingCollectorsToMap.java
package net.bench.resources.stream.to.hashmap; import java.util.HashMap; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamToMapUsingCollectorsToMap < public static void main(String[] args) < // 1. Stream of String tokens StreamnameStream = Stream.of( "Rajiv", "Anbu", "Santosh", "Abdul", "Lingaraj" ); // 2. convert Stream to Map Map map = nameStream .collect(Collectors.toMap( Function.identity(), // 1. actual String as KEY String::length, // 2. String length as their VALUE (key1, key2) -> key1) // 3. duplicate KEY resolver ); // 2.1 print to console System.out.println("1. Stream to Map conversion : \n\n" + map); // 3. convert Map to HashMap using inter-conversion constructor HashMap hMap = new HashMap<>(map); // 3.1 print to console System.out.println("\n\n2. Stream to HashMap conversion : \n\n" + hMap); > >
1. Stream to Map conversion : 2. Stream to HashMap conversion :
2. Using Collectors.toMap(keyMapper, valueMapper, mergeFunction, supplier)
- This is the 2 nd variant of Collectors.toMap() method which accepts 4 input-arguments
- Key mapper – mapping function to produce keys
- Value mapper – mapping function to produce values
- Merge Function – this is used to resolve collisions between values associated with the same key
- Supplier – function which returns a new, empty Map into which the results will be inserted
- Above method helps to convert Stream into HashMap, LinkedHashMap or TreeMap directly or whichever Supplier we pass as 4 th argument
- In the below example, we are passing HashMap implementation class as method/constructor reference HashMap::new
- Finally, print converted HashMap pairs to console
StreamToHashMapUsingCollectorsToMap.java
package net.bench.resources.stream.to.hashmap; import java.util.HashMap; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamToHashMapUsingCollectorsToMap < public static void main(String[] args) < // 1. Stream of String tokens StreamnameStream = Stream.of( "Rajiv", "Anbu", "Santosh", "Abdul", "Lingaraj" ); // 2. convert Stream to HashMap HashMap hMap = nameStream .collect(Collectors.toMap( Function.identity(), // 1. actual String as KEY String::length, // 2. String length as their VALUE (key1, key2) -> key1, // 3. duplicate KEY resolver HashMap::new // 4. implementation-class )); // 2.1 print to console System.out.println("Stream to HashMap conversion : \n\n" + hMap); > >
Stream to HashMap conversion :
Related Articles:
References :
Collecting Stream Items into Map in Java
Learn to collect Stream items into Map using Collectors.toMap() and Collectors.groupingBy() methods using Java Stream APIs.
1. Collectors.toMap() for Unique Key-value Pairs
If the stream items have the unique map key field then we can use Collectors.toMap() to collect items to Map in Map format.
For example, we can collect a list of Employee objects to Map in where employee ids are unique fields and used as keys to the Map entries.
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; public class Main < public static void main(String[] args) < ListemployeeList = new ArrayList<>(Arrays.asList( new Employee(1, "A", 100), new Employee(2, "A", 200), new Employee(3, "B", 300), new Employee(4, "B", 400), new Employee(5, "C", 500), new Employee(6, "C", 600))); Map employeesMap = employeeList.stream() .collect( Collectors.toMap(Employee::getId, Function.identity()) ); System.out.println(employeesMap); > >
2. Collectors.groupingBy() when Multiple Keys have Same Value
If the stream has items where Map keys are duplicate then we can use Collectors.groupingBy() to collect elements in Map> format. Here for each map key, we will store all elements in a List as the value.
For example, we can collect a list of Employee objects to map in where employee names may be duplicate fields for some stream elements. In such a case, all employees with the same name will be stored in a List, and the list will be stored as Map value field.
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Main < public static void main(String[] args) < ListemployeeList = new ArrayList<>(Arrays.asList( new Employee(1, "A", 100), new Employee(2, "A", 200), new Employee(3, "B", 300), new Employee(4, "B", 400), new Employee(5, "C", 500), new Employee(6, "C", 600))); Map employeesMap = employeeList.stream() .collect(Collectors.groupingBy(Employee::getName)); System.out.println(employeesMap); > >
It is very important to know beforehand if the Stream elements will have a distinct value for the map key field or not.
If map keys are duplicate and we use Collectors.toMap() method, we will get the IllegalStateException:
Exception in thread "main" java.lang.IllegalStateException: Duplicate key Employee [id=5, name=C, salary=500.0] at java.util.stream.Collectors.lambda$throwingMerger$106(Collectors.java:133) at java.util.stream.Collectors$$Lambda$3/149928006.apply(Unknown Source) at java.util.HashMap.merge(HashMap.java:1245)
Java stream collect to hashmap
Большинство операций класса Stream, которые модифицируют набор данных, возвращают этот набор в виде потока. Однако бывают ситуации, когда хотелось бы получить данные не в виде потока, а в виде обычной коллекции, например, ArrayList или HashSet. И для этого у класса Stream определен метод collect . Первая версия метода принимает в качестве параметра функцию преобразования к коллекции:
R collect(Collector collector)
Параметр R представляет тип результата метода, параметр Т — тип элемента в потоке, а параметр А — тип промежуточных накапливаемых данных. В итоге параметр collector представляет функцию преобразования потока в коллекцию.
Эта функция представляет объект Collector, который определен в пакете java.util.stream. Мы можем написать свою реализацию функции, однако Java уже предоставляет ряд встроенных функций, определенных в классе Collectors :
- toList() : преобразование к типу List
- toSet() : преобразование к типу Set
- toMap() : преобразование к типу Map
Например, преобразуем набор в потоке в список:
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; public class Program < public static void main(String[] args) < Listphones = new ArrayList(); Collections.addAll(phones, "iPhone 8", "HTC U12", "Huawei Nexus 6P", "Samsung Galaxy S9", "LG G6", "Xiaomi MI6", "ASUS Zenfone 2", "Sony Xperia Z5", "Meizu Pro 6", "Lenovo S850"); List filteredPhones = phones.stream() .filter(s->s.length() <10) .collect(Collectors.toList()); for(String s : filteredPhones)< System.out.println(s); >> >
Использование метода toSet() аналогично.
Set filteredPhones = phones.stream() .filter(s->s.length()<10) .collect(Collectors.toSet());
Для применения метода toMap() надо задать ключ и значение. Например, пусть у нас есть следующая модель:
class Phone < private String name; private int price; public Phone(String name, int price)< this.name=name; this.price=price; >public String getName() < return name; >public int getPrice() < return price; >>
Теперь применим метод toMap() :
import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; public class Program < public static void main(String[] args) < StreamphoneStream = Stream.of(new Phone("iPhone 8", 54000), new Phone("Nokia 9", 45000), new Phone("Samsung Galaxy S9", 40000), new Phone("LG G6", 32000)); Map phones = phoneStream .collect(Collectors.toMap(p->p.getName(), t->t.getPrice())); phones.forEach((k,v)->System.out.println(k + " " + v)); > > class Phone < private String name; private int price; public Phone(String name, int price)< this.name=name; this.price=price; >public String getName() < return name; >public int getPrice() < return price; >>
Лямбда-выражение p->p.getName() получает значение для ключа элемента, а t->t.getPrice() - извлекает значение элемента.
Если нам надо создать какой-то определенный тип коллекции, например, HashSet, то мы можем использовать специальные функции, которые определены в классах-коллекций. Например, получим объект HashSet:
import java.util.HashSet; import java.util.stream.Collectors; import java.util.stream.Stream; public class Program < public static void main(String[] args) < Streamphones = Stream.of("iPhone 8", "HTC U12", "Huawei Nexus 6P", "Samsung Galaxy S9", "LG G6", "Xiaomi MI6", "ASUS Zenfone 2", "Sony Xperia Z5", "Meizu Pro 6", "Lenovo S850"); HashSet filteredPhones = phones.filter(s->s.length()<12). collect(Collectors.toCollection(HashSet::new)); filteredPhones.forEach(s->System.out.println(s)); > >
Выражение HashSet::new представляет функцию создания коллекции. Аналогичным образом можно получать другие коллекции, например, ArrayList:
ArrayList result = phones.collect(Collectors.toCollection(ArrayList::new));
Вторая форма метода collect имеет три параметра:
R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)
- supplier : создает объект коллекции
- accumulator : добавляет элемент в коллекцию
- combiner : бинарная функция, которая объединяет два объекта
Применим эту версию метода collect:
import java.util.ArrayList; import java.util.stream.Collectors; import java.util.stream.Stream; public class Program < public static void main(String[] args) < Streamphones = Stream.of("iPhone 8", "HTC U12", "Huawei Nexus 6P", "Samsung Galaxy S9", "LG G6", "Xiaomi MI6", "ASUS Zenfone 2", "Sony Xperia Z5", "Meizu Pro 6", "Lenovo S850"); ArrayList filteredPhones = phones.filter(s->s.length()<12) .collect( ()->new ArrayList(), // создаем ArrayList (list, item)->list.add(item), // добавляем в список элемент (list1, list2)-> list1.addAll(list2)); // добавляем в список другой список filteredPhones.forEach(s->System.out.println(s)); > >