【发布时间】:2015-09-28 19:26:48
【问题描述】:
我用 java 流 reduce 编写了以下代码示例:
Person reducedPerson = Person.getPersons().stream()
.parallel() //will return surprising result
.reduce(new Person(), (intermediateResult, p2) -> {
intermediateResult.setAge(intermediateResult.getAge() + p2.getAge());
return intermediateResult;
},
(ir1, ir2) -> {
ir1.setAge(ir1.getAge() + ir2.getAge());
return ir1;
});
System.out.println(reducedPerson);
型号:
public class Person {
String name;
Integer age;
public Person() {
age = 0;
name = "default";
}
//...
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public static Collection<Person> getPersons() {
List<Person> persons = new ArrayList<>();
persons.add(new Person("Vasya", 12));
persons.add(new Person("Petya", 32));
persons.add(new Person("Serj", 10));
persons.add(new Person("Onotole", 18));
return persons;
}
}
每个代码示例执行返回不同的结果:
示例:
Person{name='default', age=256}
或
Person{name='default', age=248}
我已经在combiner 中定位了这个问题,因为在顺序流中代码可以正确执行。
请帮助纠正组合器。
附言
预期结果:名为“default”且年龄 72 岁的人(列表中所有 pepsons 的总和)
附言
与 reduce 结果相同的 Integer 代码可以正常工作:
Integer age = Person.getPersons().stream()
.parallel()
.reduce(0, (intermediateResult, p2) -> {
intermediateResult = intermediateResult + p2.getAge();
return intermediateResult;
}, (ir1, ir2) -> {
System.out.println("combiner");
ir1 = ir1 + ir2;
return ir1;
});
System.out.println(age);
【问题讨论】:
-
那是因为您的
reduce调用违反了合同的所有可能部分。请阅读文档。你不应该改变流中的对象。 -
是的。它应该。你不合并,你改变其中一个对象然后返回它。
-
不清楚为什么您使用
reduce的三参数版本而不是两个参数,因为累加器与您的输入类型相同。 -
@gstackoverflow 是的,这是一个独立的问题,但无论如何你都应该这样做。也就是说,为什么不写更合乎逻辑、更高效、更直接的
Person.getPersons().stream().parallel().mapToInt(Person::getAge).sum()呢?为什么需要生成Person而不是总年龄,这样更合乎逻辑? -
您是否在同一个程序中多次调用它?还是您只是重新运行整个程序并获得不同的结果?
标签: java parallel-processing java-8 java-stream reduce