java8的reduce为啥在没有使用并行流时也要输入第三个参数
搬运一个过来:
函数式编程 - java8中3个参数的reduce方法怎么理解? - SegmentFault
■网友
当然是因为没有其他的(逃
分成几步来解释把。当返回类型相同的时候为啥没有combiner,因为没有必要,即使在并行流里直接使用accumulator本身合并结果就行。那么为什么返回类型不同时需要combiner,因为即是不是并行流也有可能需要combiner,一个流的实现完全可以是先用当前的U和接下来的两个T调用两次accumulator拿到两个U,然后再用combiner合并成一个,然后下一次迭代时再用那个。或者先用identity调用accumulator把所有的T给map成U,然后再reduce出结果。
总体来说只存在3个参数且返回结果类型不同的reduce并不是因为不能有2个参数的,单纯是因为这样更合理而已。reduce的定义本身并不考虑其顺序,只考虑不管什么顺序都能拿到最终结果
■网友
占坑明天答!
直接看源码:
public final \u0026lt;R, A\u0026gt; R collect(Collector\u0026lt;? super P_OUT, A, R\u0026gt; collector) {
A container;
if (isParallel()
\u0026amp;\u0026amp; (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
\u0026amp;\u0026amp; (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) {
container = collector.supplier().get();
BiConsumer\u0026lt;A, ? super P_OUT\u0026gt; accumulator = collector.accumulator();
forEach(u -\u0026gt; accumulator.accept(container, u));
}
else {
container = evaluate(ReduceOps.makeRef(collector));
}
return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
? (R) container
: collector.finisher().apply(container);
}
设置IDENTITY_FINISH属性,表示不调用finisher函数,直接强制转换A-\u0026gt;R。
设置CONCURRENT属性,表示使用同一个容器,即使是并行流parallelStream也是如此,因为只使用一个容器,所以不会调用combiner函数,combiner函数只会到没有设置CONCURRENT属性并且是并行流的时候才会调用。不信,你把Combiner函数设置一个null就可以证明,和什么乱七八糟的返回类型相同或者不同没有关系的。
【java8的reduce为啥在没有使用并行流时也要输入第三个参数】 附带上测试代码:public class CollectorCharacteristics\u0026lt;T\u0026gt; implements Collector\u0026lt;T, Set\u0026lt;T\u0026gt;, Map\u0026lt;T, T\u0026gt;\u0026gt;{ @Override public Supplier\u0026lt;Set\u0026lt;T\u0026gt;\u0026gt; supplier() { return () -\u0026gt; { // 如果是并行流且没有设置CONCURRENT属性,则会创建多个容器 // 如果是并行流并且设置了CONCURRENT属性 或者 不是并行流 则只会创建一个容器 System.out.println( "----验证并行流\u0026amp;CONCURRENT 属性之间的关系----" ); return new HashSet\u0026lt;\u0026gt;(); }; } @Override public BiConsumer\u0026lt;Set\u0026lt;T\u0026gt;, T\u0026gt; accumulator() { return ( set, e ) -\u0026gt; { // 如果设置了CONCURRENT属性,则在accumulator一定不能出现使用set的场景,除了set.add(e) // 比如下面的打印set,由于设置了CONCURRENT属性,因此在遍历的时候,别的线程可能正在添加元素,这样就会出现并发修改异常 //System.out.println( "acc:" + set + "," + Thread.currentThread().getName() ); //System.out.println( "acc:" + "," + Thread.currentThread().getName() ); set.add( e ); }; } @Override public BinaryOperator\u0026lt;Set\u0026lt;T\u0026gt;\u0026gt; combiner() { return ( set1, set2 ) -\u0026gt; { System.out.println( "!!! combiner is called when parallelStream \u0026amp; NOT set CONCURRENT !!!\" + Thread.currentThread().getName() ); System.out.println( "set1:" + set1 ); System.out.println( "set2:" + set2 ); set1.addAll( set2 ); return set1; }; } @Override public Function\u0026lt;Set\u0026lt;T\u0026gt;, Map\u0026lt;T, T\u0026gt;\u0026gt; finisher() { return ( x ) -\u0026gt; { Map\u0026lt;T, T\u0026gt; map = new HashMap\u0026lt;\u0026gt;(); x.forEach( ( e ) -\u0026gt; map.put( e, e ) ); return map; }; } @Override public Set\u0026lt;Characteristics\u0026gt; characteristics() { // 如果finisher函数不满足identity,则不能设置IDENTITY_FINISH // 设置IDENTITY_FINISH属性,表示不调用finisher函数,直接强制转换A-\u0026gt;R // 设置CONCURRENT属性,表示使用同一个容器,即使是并行流parallelStream也是如此,因为只使用一个容器,所以不会调用combiner函数 return Collections.unmodifiableSet( EnumSet.of( UNORDERED ) ); } public static void main( String args ) { Map\u0026lt;String, String\u0026gt; map = null; List\u0026lt;String\u0026gt; strs = Arrays.asList( "hello", "world", "welcome", "a", "b", "c", "b" ); System.out.println( Runtime.getRuntime().availableProcessors() ); for( int i = 0; i \u0026lt; 100; ++i ) { //map = strs.stream().collect( new CollectorCharacteristics\u0026lt;\u0026gt;() ); map = strs.parallelStream().collect( new CollectorCharacteristics\u0026lt;\u0026gt;() ); System.out.println( map ); } System.out.println( "===================" ); System.out.println( map ); }}
推荐阅读
- 为啥看到书柜上的藏书会有心旷神怡的感觉
- 为啥知乎上普便有一种【我在北上广深打工,所以拥有更好的视野】这样的错觉
- 为啥工商银行的用户体验如此之差
- 汽车|看了中消协4S店服务测评调查结果,终于知道法系车为啥卖不好了
- 你为啥从窝窝商城离职?
- 为啥5G和2.4G默认的BSSID是相同的
- 为啥电器实体店的价格比淘宝贵那么多
- 现在在线学习视频有很多了,为啥大部分人还是喜欢下载下来观看
- 为啥到现在你还没有女朋友 ?
- 天赐的声音|33岁张雨绮为啥总离婚?看过这些照片就明白了,都是性感惹得祸
