In this article, we will discuss how to convert Stream into a ConcurrentHashMap in Java 1.8 version using Stream API
Stream to ConcurrentHashMap :
Using Collectors.toConcurrentMap() method, we can convert Stream into a Concurrent Map. There are 3 variants of Collectors.toConcurrentMap() method,
- Collectors.toConcurrentMap(keyMapper, valueMapper)
- Collectors.toConcurrentMap(keyMapper, valueMapper, mergeFunction)
- Collectors.toConcurrentMap(keyMapper, valueMapper, mergeFunction, supplier)
1. Using Collectors.toConcurrentMap(keyMapper, valueMapper)
- First variant of Collectors.toConcurrentMap() method which accepts 2 input-arguments
- Key mapper – mapping function to produce keys
- Value mapper – mapping function to produce values
- Above method helps to convert Stream into ConcurrentMap
- For converting into ConcurrentHashMap, create ConcurrentHashMap object and pass above obtained ConcurrentMap as constructor-argument
- Finally, print converted ConcurrentHashMap pairs to console
- Note: If the mapped keys contains duplicates (according to
Object.equals(Object)
), anIllegalStateException
is thrown when the collection operation is performed - To manage dupicate case scenario, use
toConcurrentMap(Function, Function, BinaryOperator)
instead which is the 2nd variant explained below - Caution: use this variant only when there are no duplicates
StreamToConcurrentMap.java
package net.bench.resources.stream.to.concurrenthashmap;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.stream.Collectors;
public class StreamToConcurrentMap {
public static void main(String[] args) {
// 1. List of String
List<String> list = Arrays.asList(
"Rajiv",
"Rajiv",
"Anbu",
"Santosh",
"Abdul",
"Lingaraj"
);
// 2. 1st variant - convert Stream<String> to ConcurrentMap<String, Integer>
ConcurrentMap<String, Integer> concurrentMap = list
.parallelStream() // parallel stream
.collect(Collectors.toConcurrentMap(
Function.identity(), // 1. actual String as KEY
String::length // 2. String length as their VALUE
));
// 3. print to console
System.out.println("Stream to ConcurrentMap conversion : \n\n"
+ concurrentMap);
}
}
Output:
Exception in thread "main" java.lang.IllegalStateException: java.lang.IllegalStateException:
Duplicate key 5
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl
.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl
.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735)
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:583)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:496)
at net.bench.resources.stream.to.concurrenthashmap.StreamToConcurrentMap
.main(StreamToConcurrentMap.java:27)
Caused by: java.lang.IllegalStateException: Duplicate key 5
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.concurrent.ConcurrentHashMap.merge(ConcurrentHashMap.java:1990)
at java.util.stream.Collectors.lambda$toConcurrentMap$59(Collectors.java:1472)
at java.util.stream.ReferencePipeline.lambda$collect$1(ReferencePipeline.java:496)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
2. Using Collectors.toConcurrentMap(keyMapper, valueMapper, mergeFunction)
- This is the 2nd variant of Collectors.toConcurrentMap() method which 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 ConcurrentMap
- For converting into ConcurrentHashMap, create ConcurrentHashMap object and pass above obtained ConcurrentMap as constructor-argument
- Finally, print converted ConcurrentHashMap pairs to console
StreamToConcurrentMapUsingCollectorsToConcurrentMap.java
package net.bench.resources.stream.to.concurrenthashmap;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.stream.Collectors;
public class StreamToConcurrentMapUsingCollectorsToConcurrentMap {
public static void main(String[] args) {
// 1. List of String
List<String> list = Arrays.asList(
"Rajiv",
"Anbu",
"Santosh",
"Abdul",
"Lingaraj"
);
// 2. convert Stream<String> to ConcurrentMap<String, Integer>
ConcurrentMap<String, Integer> concurrentMap = list
.parallelStream() // parallel stream
.collect(Collectors.toConcurrentMap(
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 ConcurrentMap conversion : \n\n"
+ concurrentMap);
// 3. convert ConcurrentMap to ConcurrentHashMap using inter-conversion constructor
ConcurrentHashMap<String, Integer> concurrentHashMap =
new ConcurrentHashMap<>(concurrentMap);
// 3.1 print to console
System.out.println("\n\n2. Stream to ConcurrentHashMap conversion : \n\n"
+ concurrentHashMap);
}
}
Output:
1. Stream to ConcurrentMap conversion :
{Lingaraj=8, Abdul=5, Rajiv=5, Santosh=7, Anbu=4}
2. Stream to ConcurrentHashMap conversion :
{Lingaraj=8, Abdul=5, Rajiv=5, Santosh=7, Anbu=4}
3. Using Collectors.toConcurrentMap(keyMapper, valueMapper, mergeFunction, supplier)
- This is the 3rd variant of Collectors.toConcurrentMap() 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 ConcurrentHashMap directly or whichever Supplier we pass as 4th argument
- In the below example, we are passing ConcurrentHashMap implementation class as method/constructor reference ConcurrentHashMap::new
- Finally, print converted ConcurrentHashMap pairs to console
StreamToConcurrentHashMapUsingCollectorsToConcurrentMap.java
package net.bench.resources.stream.to.concurrenthashmap;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
public class StreamToConcurrentHashMapUsingCollectorsToConcurrentMap {
public static void main(String[] args) {
// 1. List of String
List<String> list = Arrays.asList(
"Rajiv",
"Anbu",
"Santosh",
"Abdul",
"Lingaraj"
);
// 2. convert Stream<String> to ConcurrentHashMap<String, Integer>
ConcurrentHashMap<String, Integer> concurrentHashMap = list
.parallelStream() // parallel stream
.collect(Collectors.toConcurrentMap(
Function.identity(), // 1. actual String as KEY
String::length, // 2. String length as their VALUE
(key1, key2) -> key1, // 3. duplicate KEY resolver
ConcurrentHashMap::new // 4. implementation-class
));
// 2.1 print to console
System.out.println("Stream to ConcurrentHashMap conversion : \n\n"
+ concurrentHashMap);
}
}
Output:
Stream to ConcurrentHashMap conversion :
{Lingaraj=8, Abdul=5, Rajiv=5, Santosh=7, Anbu=4}
Related Articles:
- Java 8 – Convert Stream to HashMap
- Java 8 – Convert Stream to LinkedHashMap
- Java 8 – Convert Stream to TreeMap
- Java 8 – Convert Stream to ConcurrentHashMap
References :
- https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toConcurrentMap-java.util.function.Function-java.util.function.Function-
- https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toConcurrentMap-java.util.function.Function-java.util.function.Function-java.util.function.BinaryOperator-
- https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toConcurrentMap-java.util.function.Function-java.util.function.Function-java.util.function.BinaryOperator-java.util.function.Supplier-
Happy Coding !!
Happy Learning !!