Home  >  Java 10

Convert Java Stream to Map

By Arvind Rai, October 13, 2020
On this page we will learn how to convert Java Stream to Map. Java Stream.collect performs a mutable reduction operation on the elements using a Collector.
<R,A> R collect(Collector<? super T,A,R> collector) 
To collect stream into Map, we need to pass Collector as argument achieved by calling following methods.
1. Collectors.toMap
2. Collectors.toConcurrentMap
3. Collectors.toUnmodifiableMap
4. Collectors.groupingBy
Now let us discuss the use of above methods to convert stream into map.

1. Using Collectors.toMap

The Collectors.toMap returns a Collector that accumulates elements into a Map whose keys and values are obtained by provided mapping functions to the input elements. It has following variants.
a. If the keys are duplicates, an IllegalStateException is thrown when the collection operation is performed.
public static <T,K,U> Collector<T,?,Map<K,U>> toMap(
            Function<? super T,? extends K> keyMapper,
            Function<? super T,? extends U> valueMapper) 
Find the example.
ExampleToMap1.java
package com.concretepage;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class ExampleToMap1 {
  public static void main(String[] args) {
	Map<Integer, Integer> map1 = Stream.of(10, 15, 20)
		.collect(Collectors.toMap(i -> i, i -> i * 2)); 
	System.out.println(map1);

	Map<Integer, Integer> map2 = IntStream.range(20,  25).boxed()
		.collect(Collectors.toMap(i -> i + 2, i -> i * 5));
	System.out.println(map2);
	
	Map<Integer, String> map3 = Arrays.asList(1, 2, 3).stream().map(i -> i * 2)
		.collect(Collectors.toMap(i -> i * 10, i -> "A" + i));
	System.out.println(map3);	
  }
} 
Output
{20=40, 10=20, 15=30}
{22=100, 23=105, 24=110, 25=115, 26=120}
{20=A2, 40=A4, 60=A6} 
b. For duplicates keys, the value mapping function is applied to each equal element and the results are merged using the provided merging function.
public static <T,K,U> Collector<T,?,Map<K,U>> toMap(
            Function<? super T,? extends K> keyMapper,
            Function<? super T,? extends U> valueMapper,
            BinaryOperator<U> mergeFunction) 
Example:
ExampleToMap2.java
package com.concretepage;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ExampleToMap2 {
  public static void main(String[] args) {
	Map<Integer, Integer> map1 = Stream.of(10, 10, 15, 20)
		.collect(Collectors.toMap(i -> i, i -> i * 2, (x, y) -> x + y)); 
	System.out.println(map1);
	
	Map<Integer, String> map2 = Arrays.asList(1, 1, 2, 2, 3).stream().map(i -> i * 2)
		.collect(Collectors.toMap(i -> i * 10, i -> "A" + i, (x, y) -> x + "-" + y));
	System.out.println(map2);
  }
} 
Output
{20=40, 10=40, 15=30}
{20=A2-A2, 40=A4-A4, 60=A6} 
c. For duplicates keys, the value mapping function is applied to each equal element and the results are merged using the provided merging function. The Map is created by provided supplier function.
public static <T,K,U,M extends Map<K,U>> Collector<T,?,M> toMap(
            Function<? super T,? extends K> keyMapper,
            Function<? super T,? extends U> valueMapper,
            BinaryOperator<U> mergeFunction, Supplier<M> mapFactory) 
Example: Here in the example we will sort a stream and then return a LinkedHashMap passing as supplier to retain the sorted value.
ExampleToMap3.java
package com.concretepage;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class ExampleToMap3 {
  public static void main(String[] args) {
	Map<Integer, String> map2 = Arrays.asList(15, 10, 10, 20).stream().sorted()
		.collect(Collectors.toMap(i -> i, i -> "A" + i, (x, y) -> x + "-" + y, LinkedHashMap::new));
	System.out.println(map2);
  }
} 
Output
{10=A10-A10, 15=A15, 20=A20} 

2. Using Collectors.toConcurrentMap

The Collectors.toConcurrentMap returns a concurrent Collector that accumulates elements into a ConcurrentMap whose keys and values are obtained by provided mapping functions to the input elements.
The Collectors.toConcurrentMap uses the same variant of arguments as Collectors.toMap as following.
(i) keyMapper, valueMapper
(ii) keyMapper, valueMapper, mergeFunction
(iii) keyMapper, valueMapper, mergeFunction, mapFactory

Find the example.
ExampleToConcurrentMap.java
package com.concretepage;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ExampleToConcurrentMap {
  public static void main(String[] args) {
	ConcurrentMap<Integer, Integer> map1 = Stream.of(10, 15, 20)
		.collect(Collectors.toConcurrentMap(i -> i, i -> i * 2)); 
	System.out.println(map1);
	
	ConcurrentMap<Integer, String> map2 = Stream.of(1, 2, 2, 3, 3)
		.collect(Collectors.toConcurrentMap(i -> i * 10, i -> "A" + i, (x, y) -> x + "-" + y));
	System.out.println(map2);	
	
	ConcurrentMap<Integer, String> map3 = Stream.of(15, 10, 10, 20)
		.collect(Collectors.toConcurrentMap(i -> i, i -> "A" + i, (x, y) -> x + "-" + y, ConcurrentHashMap::new));
	System.out.println(map3);	
  }
} 
Output
{20=40, 10=20, 15=30}
{20=A2-A2, 10=A1, 30=A3-A3}
{20=A20, 10=A10-A10, 15=A15} 

3. Using Collectors.toUnmodifiableMap

The Collectors.toUnmodifiableMap returns a Collector that accumulates elements into an unmodifiable Map whose keys and values are obtained by provided mapping functions to the input elements. To handle duplicate keys we can pass mergeFunction in the same way as in Collectors.toMap. The Collectors.toUnmodifiableMap can accept following variant of arguments.
(i) keyMapper, valueMapper
(ii) keyMapper, valueMapper, mergeFunction

Example:
ExampleToUnmodifiableMap.java
package com.concretepage;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ExampleToUnmodifiableMap {
  public static void main(String[] args) {
	Map<Integer, Integer> map1 = Stream.of(10, 15, 20)
		.collect(Collectors.toUnmodifiableMap(i -> i, i -> i * 2)); 
	System.out.println(map1);
	
	Map<Integer, String> map2 = Stream.of(1, 1, 2, 2, 3).map(i -> i * 2)
		.collect(Collectors.toUnmodifiableMap(i -> i * 10, i -> "A" + i, (x, y) -> x + "-" + y));
	System.out.println(map2);
  }
} 
Output
{20=40, 15=30, 10=20}
{20=A2-A2, 40=A4-A4, 60=A6} 

4. Using Collectors.groupingBy

The Collectors.groupingBy returns a Collector implementing a "group by" operation on input elements for a type and groups elements according to a classification function and returns result as Map.
Find the Collectors.groupingBy method declaration from Java doc.
public static <T,K> Collector<T,?,Map<K,List<T>>> groupingBy(Function<? super T,? extends K> classifier) 
Example
ExampleGroupingBy.java
package com.concretepage;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ExampleGroupingBy {
  public static void main(String[] args) {
      Person p1 = new Person(20, "Mahesh");
      Person p2 = new Person(25, "Krishn");
      Person p3 = new Person(20, "Nilesh");
      Person p4 = new Person(25, "Bharat");
      
      Map<Integer, List<Person>> personByAge = Stream.of(p1, p2, p3, p4)
          .collect(Collectors.groupingBy(Person::getAge));
      System.out.println(personByAge);
  }
}
class Person { 
  private int age;
  private String name;
  public Person(int age, String name) {
	this.age = age;
	this.name = name;
  }
  //Sets, Gets
  
  @Override
  public String toString() {
	return age + "-" + name;
  }
} 
Output
{20=[20-Mahesh, 20-Nilesh], 25=[25-Krishn, 25-Bharat]} 

5. References

Stream
Collectors
POSTED BY
ARVIND RAI
ARVIND RAI








©2020 concretepage.com | Privacy Policy | Contact Us