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

时间:2015-10-27 18:01:51

标签: java java-8 java-stream reduce

我有这个代码a:

 print("Response data: \(JSON[1]["Name"] as! String)")

和此代码b:

        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);
                });

我所做的就是创建响应对象,然后将它们转换为comaprisonResult对象并将它们缩减为一个comaprisonResult。

代码 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); }); 显示了一个正确的int类成员a

代码comparisonResults.num_of_sub_responses==5显示一个int类成员b,它是正确结果的两倍。

java 8 reduce应该是线程安全的,对吧?

我错过了什么吗?

comparisonResults.num_of_sub_responses==10getResponse是线程安全的

2 个答案:

答案 0 :(得分:7)

您正在改变reduce中的传入对象。这是错的。在修改传入对象之后创建新对象没有任何帮助。

你想做什么,是

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

如果.map(item -> compareToBl(item))的结果为ComparisonResults,或者换句话说,addSingleResult合并了两个ComparisonResults个实例,则可以使用ComparisonResults::addSingleResult作为合并功能,虽然它的名字有点误导。

你应该仔细阅读“Reduction” chapter of the documentation及其后续行动,“可变减少”。

答案 1 :(得分:2)

reduce操作reduce(identity, operator)依赖于关于你传递它的参数的两个重要假设。

  1. 第一个参数是标识。也就是说,当您在任何项目和给定的identity之间使用reduce运算符时,您将获得原始项目。
  2. 操作员是关联的。
  3. 这两个假设在使用并行流时非常重要,因为一般来说,它的作用是:

    • 为每个线程分配流
    • 每个线程都以标识开头,并使用流中的元素累积结果:

      result = identity op element1 op element2 op element3 ...
      
    • 然后使用运算符将​​来自不同线程的结果组合在一起:

      grand result = result1 op result2 op result3
      

    因此,假设您正在对数字求和,它会将5 + 4 + 3 + 20之类的操作分解为( 0 + 5 + 4 ) + ( 0 + 3 + 20 )。当且仅当上述假设成立时才有效。 (0是加法的标识,加法是关联的)。

    但是通过改变运算符中的第一个操作数,这意味着您实际上正在改变身份对象。因此,它不再被视为身份。那是op(identity,result)并没有给你与result本身相同的价值。

    如果操作员不是关联的,那么问题将在“宏观结果”阶段出现。