简体   繁体   English

为什么Java流映射减少了两次我的结果?

[英]Why does Java stream map reduce count my result twice?

I have this code a: 我有这个代码:

        ComparisonResults comparisonResults = requestsList
                .stream()
                .map(item -> getResponse(item))
                .map(item -> compareToBl(item))
                .reduce(new ComparisonResults(), (result1, result2) ->
                {
                     result1.addSingleResult(result2);
                 //   return result1;
                    return new ComparisonResults(result1);
                });

and this code b: 这个代码b:

        ComparisonResults comparisonResults = requestsList
                .parallelStream()
                .map(item -> getResponse(item))
                .map(item -> compareToBl(item))
                .reduce(new ComparisonResults(), (result1, result2) ->
                {
                     result1.addSingleResult(result2);
                 //   return result1;
                    return new ComparisonResults(result1);
                });

All I do is to create response objects, then transform them to comaprisonResult objects and to reduce them to one comaprisonResult. 我所做的就是创建响应对象,然后将它们转换为comaprisonResult对象并将它们减少为一个comaprisonResult。

code a shows an int class member comparisonResults.num_of_sub_responses==5 which is correct 代码a显示了一个int类成员comparisonResults.num_of_sub_responses==5这是正确的

code b shows an int class member comparisonResults.num_of_sub_responses==10 which is double the correct result. 代码b显示了一个int类成员comparisonResults.num_of_sub_responses==10 ,它是正确结果的两倍。

java 8 reduce should be thread safe, right? java 8 reduce应该是线程安全的吧?

am i missing anything? 我错过了什么吗?

getResponse and compareToBl are thread safe getResponsecompareToBl是线程安全的

Your are mutating an incoming object in reduce . 你正在改变reduce的传入对象。 This is wrong. 这是错的。 It doesn't help that you are creating a new object after modifying the incoming object. 修改传入对象创建新对象没有任何帮助。

What you want to do, is 你想做什么,是

.collect(ComparisonResults::new, ComparisonResults::addSingleResult,
         (a,b)->/* code to merge two ComparisonResults instances*/);

If the result of .map(item -> compareToBl(item)) is ComparisonResults or, in other words, addSingleResult merges two ComparisonResults instances, you can use ComparisonResults::addSingleResult as merge function, though it's name is a bit misleading then. 如果.map(item -> compareToBl(item))ComparisonResults或者换句话说, addSingleResult合并两个ComparisonResults实例,则可以使用ComparisonResults::addSingleResult作为合并函数,尽管它的名称有点误导。

You should carefully read the “Reduction” chapter of the documentation and its follow-up, “Mutable reduction”. 您应该仔细阅读文档及其后续“可变缩减”的“缩减”章节

The reduce operation reduce(identity, operator) relies on two important assumptions about the arguments you pass it. reduce操作reduce(identity, operator)依赖于关于你传递它的参数的两个重要假设。

  1. The first parameter is an identity . 第一个参数是身份 That is, when you use the reducing operator between any item and the given identity , you get the original item. 也就是说,当您在任何项目和给定identity之间使用reduce运算符时,您将获得原始项目。
  2. The operator is associative. 运营商是关联的。

These two assumptions are very important when working with a parallel stream, because in general, what it does is: 使用并行流时,这两个假设非常重要,因为一般来说,它的作用是:

  • Give each thread a slice of the stream 为每个线程分配一个流
  • Each thread starts with the identity, and accumulates a result using the elements in the stream: 每个线程都以标识开头,并使用流中的元素累积结果:

     result = identity op element1 op element2 op element3 ... 
  • Then the results from different threads are combined together using the operator: 然后使用运算符将​​来自不同线程的结果组合在一起:

     grand result = result1 op result2 op result3 

So, suppose you were summing numbers, it breaks an operation like 5 + 4 + 3 + 20 into ( 0 + 5 + 4 ) + ( 0 + 3 + 20 ) . 所以,假设你在对数字进行求和,它会将5 + 4 + 3 + 20类的操作分解为( 0 + 5 + 4 ) + ( 0 + 3 + 20 ) Which works if, and only if, the above assumptions are true. 当且仅当上述假设成立时才有效。 (0 is the identity for addition, addition is associative). (0是加法的标识,加法是关联的)。

But by mutating the first operand inside your operator, it means that you are actually mutating the identity object. 但是通过改变运算符内的第一个操作数,这意味着您实际上正在改变身份对象。 So it cannot be considered an identity anymore. 因此它不再被视为身份 That is op(identity,result) does not give you the same value as result itself. 那就是op(identity,result)不会给你与result本身相同的值。

If the operator is not associative, problems will turn up in the "grand result" stage. 如果操作员不是关联的,那么问题将在“大结果”阶段出现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM