Collectors.toConcurrentMap和通过Collectors.toMap供应商选项将Map转换为ConcurrentHashMap有什么区别?

Kay*_*ayV 6 java concurrenthashmap java-8 java-stream collectors

我想将a Map转换为ConcurrentHashMap通过Java 8 StreamCollector接口,我可以使用两个选项.

首先:

Map<Integer, String> mb = persons.stream()
                                 .collect(Collectors.toMap(
                                            p -> p.age, 
                                            p -> p.name, 
                                            (name1, name2) -> name1+";"+name2,
                                            ConcurrentHashMap::new));
Run Code Online (Sandbox Code Playgroud)

第二个:

Map<Integer, String> mb1 = persons.stream()
                                  .collect(Collectors.toConcurrentMap(
                                             p -> p.age, 
                                             p -> p.name));
Run Code Online (Sandbox Code Playgroud)

哪一个是更好的选择?我什么时候应该使用每个选项?

Eug*_*ene 12

处理并行流时它们之间存在差异.

toMap - >是非并发收集器

toConcurrentMap - >是一个并发收集器(这可以从他们的特征中看出).

所不同的是toMap将创建的多个中间结果,然后然后将合并到一起(例如收集器的供应商将被多次调用),而toConcurrentMap将创建一个结果,并且每个线程将扔掉它的结果(这些供应商收集器只会被调用一次)

为什么这很重要?这涉及插入顺序(如果重要).

toMap将通过合并多个中间结果在遭遇顺序中在结果Map中插入值(该收集器的供应商多次调用以及Combiner)

toConcurrentMap将通过将所有元素抛出到公共结果容器(在本例中为ConcurrentHashMap)以任何顺序(未定义)收集元素.供应商只召集一次,Accumulator多次召唤,而Combiner永远不召唤.

这里的一个小警告是,CONCURRENT收集器不要调用合并:要么流必须有UNORDERED标志 - 要么通过unordered()显式调用,要么没有订购流的源(Set例如).

  • @Bolzano在非并行流中,Combiner不会被调用任何一个实现.合并将在累加器中完成(称为您拥有的许多元素,而供应商只会被调用一次).所以是的,唯一可见的区别是你得到的结果:一个HashMap与一个ConcurrentHashMap.引擎盖下的toMap调用HashMap :: merge,而toConcurrentMap调用ConcurrentHashMap :: merge.所以,如果你正在进行串行处理,为什么你会想要ConcurrentHashMap? (2认同)

Era*_*ran 6

来自toMap的Javadoc:

返回的收集器不是并发的.对于并行流管道,组合器功能通过将键从一个映射合并到另一个映射来操作,这可能是昂贵的操作.如果不需要将结果以遭遇顺序插​​入到Map中,则使用toConcurrentMap(Function,Function)可以提供更好的并行性能.

toConcurrentMap 不会在遇到顺序中将结果插入到Map中,但应该提供更好的性能.

如果您不关心插入顺序,建议toConcurrentMap您在使用并行流时使用.