I want to convert a Map
into a ConcurrentHashMap
via Java 8 Stream
and Collector
interface, and there are two options I can use.
The first:
Map<Integer, String> mb = persons.stream()
.collect(Collectors.toMap(
p -> p.age,
p -> p.name,
(name1, name2) -> name1+";"+name2,
ConcurrentHashMap::new));
And the second:
Map<Integer, String> mb1 = persons.stream()
.collect(Collectors.toConcurrentMap(
p -> p.age,
p -> p.name));
Which one is the better option? When should I use each option?
There is a difference between them when dealing with parallel streams.
toMap
-> is a non-concurrent collector
toConcurrentMap
-> is a concurrent collector (this can be seen from their characteristics).
The difference is that toMap will create multiple intermediate results and then will merge then together (the Supplier of such a Collector will be called multiple times), while toConcurrentMap will create a single result and each Thread will throw results at it (the Supplier of such a Collector will be called only once)
Why is this important? This deals with insertion order (if that matters).
toMap will insert values in the resulting Map in encounter order by merging multiple intermediate results (Supplier of that collector is called multiple time as well as the Combiner)
toConcurrentMap will collect elements in any order (undefined) by throwing all elements at a common result container (ConcurrentHashMap in this case). Supplier is called only once, Accumulator many times and Combiner never.
The small caveat here is that for a CONCURRENT
collector to not invoke the merger: either the stream has to have the UNORDERED
flag - either via the unordered()
explicit call or when the source of the stream is not ordered (a Set
for example).