Java 流 API 提供了一种通用.reduce(identity, accumulator)方法。
从 javadocs 中可以清楚地看出累加器应该是一个无状态函数。
但是,我有一个关于identity对象的问题,即它应该是线程安全的吗?
假设 anidentity是一个 java 对象,并且 anaccumulator以修改不是原子的方式修改该对象,例如accumulator查看identity's状态,然后决定如何准确地修改它的内部状态。很明显,可能会同时运行多个 reduce 操作。在这种情况下,会出现几个问题:
identity对象范围内是原子的吗?identity对象不可变并在每次减少时返回一个新实例就足够了吗?我继续学习java 8.
我发现了有趣的行为:
让我们看看代码示例:
// identity value and accumulator and combiner
Integer summaryAge = Person.getPersons().stream()
//.parallel() //will return surprising result
.reduce(1, (intermediateResult, p) -> intermediateResult + p.age,
(ir1, ir2) -> ir1 + ir2);
System.out.println(summaryAge);
Run Code Online (Sandbox Code Playgroud)
和模型类:
public class Person {
String name;
Integer 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;
}
}
Run Code Online (Sandbox Code Playgroud)
12 + 32 + 10 + 18 = 72
对于序列流,此代码始终返回73(72 …
我正在学习Java 8,在包摘要的Reduction操作部分中java.util.stream,它说:
更正式地说,标识值必须是组合器函数的标识。这意味着对于所有 u,combiner.apply(identity, u) 等于 u。此外,组合器函数必须是关联的,并且必须与累加器函数兼容:对于所有 u 和 t,combiner.apply(u,accumulator.apply(identity, t)) 必须是 equals() 到accumulator.apply(u, t)。
我不明白为什么标识值必须是组合器函数的标识。我认为“组合器函数必须是关联的并且必须是兼容的”足以产生相同的结果,无论流是串行还是并行。
例如,我有一个包含四个元素的流e1, e2, e3, e4。如果是串行流,则结果为identityac e1ac e2ac e3ac e4(ac表示累加器函数)。如果是并行流,则四个元素可以分成两部分,[e1, e2]和[e3, e4],所以结果是 ( identityac e1ac e2) co ( identityac e3ac e4)。
如果给定“组合器函数是关联的并且与累加器函数兼容”,我们可以推断“ identityac e1ac e2ac e3ac e4”等于“( identityac e1ac e2) co ( …
我试图理解为什么这个例子的结果总是如此,这是我的例子:
String s1 = Arrays.asList("A", "E", "I", "O", "U").stream()
.reduce("", String::concat);
String s2 = Arrays.asList("A", "E", "I", "O", "U").parallelStream()
.reduce("", String::concat);
System.out.println(s1.equals(s2));
Run Code Online (Sandbox Code Playgroud)
这总是打印true,我所知道的是使用 parallelStream 我们无法预测结果有人可以解释为什么吗?
以下代码输出始终为24.
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<String>();
list.add("java");
list.add("php");
list.add("python");
list.add("perl");
list.add("c");
list.add("lisp");
list.add("c#");
int s = list.stream().reduce(0, (x, y) -> x + y.length(), (x, y) -> 0);
System.out.println(s);
s = list.stream().reduce(0, (x, y) -> x + y.length(), (x, y) -> x - y);
System.out.println(s);
s = list.stream().reduce(0, (x, y) -> x + y.length(), (x, y) -> x * y);
System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)
问题是组合器影响我的代码的原因.
并行运行时 a==b 为何为 false 但与组合器一起使用时却有效?
public class test {
public static int cal(final int i) {
return 1;
}
public static void main(String args[]) {
int a = IntStream.range(0, 3).reduce(0, (abc, cde) -> abc + cal(cde));
int b = IntStream.range(0, 3).parallel().reduce(0, (abc, cde) -> abc + cal(cde));
System.out.println(a == b); // false
int c = List.of(0, 1, 2).stream().parallel().reduce(0, (abc, cde) -> abc + cal(cde), Integer::sum);
System.out.println(a == c); // true
}
}
Run Code Online (Sandbox Code Playgroud)