In this tutorial you’ll see how to convert a Java Stream to Map using collector method and the utility methods provided by Collectors like Collectors.toMap() and Collectors.groupingBy().
Collectors.toMap() method in Java Stream
Collectors.toMap() is overloaded and it has following variants-
1. Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)- Accumulates stream elements into a Map whose keys and values are the result of applying the provided mapping functions to the input elements.
Mapping functions which are passed as parameter are-
- keyMapper- a mapping function to produce keys
- valueMapper- a mapping function to produce values
Method returns a Collector which collects elements into a Map
2. Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)- This variant of toMap() is used if the mapped keys contain duplicates, in that case the value mapping function is applied to each equal element and the results are merged using the provided merging function.
3. Collector<T,?,M> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapFactory)- This toMap() method is used if you want to specify the type of Map in which elements are stored. The Map is created by a provided supplier function.
Collectors.toMap() Java examples
1. In the following example a list of employees is collected to a Map where key is the employeeID and value is the employee object itself.
Employee class
public class Employee { private String empId; private int age; private String name; private char gender; private int salary; Employee(String empId, int age, String name, char gender, int salary){ this.empId = empId; this.age = age; this.name = name; this.gender = gender; this.salary = salary; } public String getEmpId() { return empId; } public int getAge() { return age; } public String getName() { return name; } public char getGender() { return gender; } public int getSalary() { return salary; } @Override public String toString() { return "Emp Id: " + getEmpId() + " Name: " + getName() + " Age: " + getAge(); } }
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; public class StreamToMap { public static void main(String[] args) { List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), new Employee("E002", 35, "Shelly", 'F', 7000), new Employee("E003", 24, "Mark", 'M', 9000), new Employee("E004", 37, "Ritu", 'F', 11000), new Employee("E005", 32, "Anuj", 'M', 12000), new Employee("E006", 28, "Amy", 'F', 14000)); Map<String, Employee> empMap = empList.stream() .collect(Collectors.toMap(Employee::getEmpId, Function.identity())); // To check type of Map System.out.println(empMap.getClass().getName()); System.out.println(empMap); } }
Output
java.util.HashMap {E005=Emp Id: E005 Name: Anuj Age: 32, E006=Emp Id: E006 Name: Amy Age: 28, E001=Emp Id: E001 Name: Ram Age: 40, E002=Emp Id: E002 Name: Shelly Age: 35, E003=Emp Id: E003 Name: Mark Age: 24, E004=Emp Id: E004 Name: Ritu Age: 37}
Though the Javadocs say “There are no guarantees on the type, mutability, serializability, or thread-safety of the Map returned.” but usually HashMap is returned as checked in the example by printing type of the Map. To specify different Map type you can use the toMap() method with four arguments.
2. In the following example a list of employees is collected to a Map where key is the gender of the employee and value is the employee name. Here we’ll have duplicates in the key value so we can use the toMap() method with three arguments and specify the merging function which is of type BinaryOperator functional interface.
public class StreamToMap { public static void main(String[] args) { List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), new Employee("E002", 35, "Shelly", 'F', 7000), new Employee("E003", 24, "Mark", 'M', 9000), new Employee("E004", 37, "Ritu", 'F', 11000), new Employee("E005", 32, "Anuj", 'M', 12000), new Employee("E006", 28, "Amy", 'F', 14000)); Map<Character, String> empMap = empList.stream() .collect(Collectors.toMap(Employee::getGender, Employee::getName, (a, b) -> a + ", " + b)); System.out.println(empMap); } }
Output
{F=Shelly, Ritu, Amy, M=Ram, Mark, Anuj}
3. In case you want to collect to another type of Map for example TreeMap then you can use the toMap() method with four parameters.
public class StreamToMap { public static void main(String[] args) { List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), new Employee("E002", 35, "Shelly", 'F', 7000), new Employee("E003", 24, "Mark", 'M', 9000), new Employee("E004", 37, "Ritu", 'F', 11000), new Employee("E005", 32, "Anuj", 'M', 12000), new Employee("E006", 28, "Amy", 'F', 14000)); Map<Character, String> empMap = empList.stream() .collect(Collectors.toMap(Employee::getGender, Employee::getName, (a, b) -> a + ", " + b, TreeMap::new)); // To check type of Map System.out.println(empMap.getClass().getName()); System.out.println(empMap); } }
Output
java.util.TreeMap {F=Shelly, Ritu, Amy, M=Ram, Mark, Anuj}
As you can see now type of the Map is TreeMap.
Stream to Map using Collectors.groupingBy()
Collectors.groupingBy() method returns a collector that produces a Map<K, List<T>> whose keys are the values resulting from applying the classification function to the input elements and corresponding values for each groups are stored in Lists. In the scenario of duplicate keys groupingBy() method is also one option to group elements into different lists.
For example if you have a list of employees and you want to group objects on the basis of gender.
public class StreamToMap { public static void main(String[] args) { List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), new Employee("E002", 35, "Shelly", 'F', 7000), new Employee("E003", 24, "Mark", 'M', 9000), new Employee("E004", 37, "Ritu", 'F', 11000), new Employee("E005", 32, "Anuj", 'M', 12000), new Employee("E006", 28, "Amy", 'F', 14000)); Map<Character, List<Employee>> empMap = empList.stream() .collect(Collectors.groupingBy(Employee::getGender)); System.out.println(empMap); } }
Output
java.util.HashMap {F=[Emp Id: E002 Name: Shelly Age: 35, Emp Id: E004 Name: Ritu Age: 37, Emp Id: E006 Name: Amy Age: 28], M=[Emp Id: E001 Name: Ram Age: 40, Emp Id: E003 Name: Mark Age: 24, Emp Id: E005 Name: Anuj Age: 32]}
That's all for this topic Java Stream - Convert Stream to Map. If you have any doubt or any suggestions to make please drop a comment. Thanks!
>>>Return to Java Advanced Tutorial Page
Related Topics
You may also like-
No comments:
Post a Comment