我目前正在阅读O'reilly
Java 8 Lambdas 是一本非常好的书。我遇到过这样的例子。
我有一个
private final BiFunction<StringBuilder,String,StringBuilder>accumulator=
(builder,name)->{if(builder.length()>0)builder.append(",");builder.append("Mister:").append(name);return builder;};
final Stream<String>stringStream = Stream.of("John Lennon","Paul Mccartney"
,"George Harrison","Ringo Starr");
final StringBuilder reduce = stringStream
.filter(a->a!=null)
.reduce(new StringBuilder(),accumulator,(left,right)->left.append(right));
System.out.println(reduce);
System.out.println(reduce.length());
这会产生正确的输出。
Mister:John Lennon,Mister:Paul Mccartney,Mister:George Harrison,Mister:Ringo Starr
我的问题被reduce
方法视为最后一个参数BinaryOperator
我的问题是这个参数用于哪个?如果我改变
.reduce(new StringBuilder(),accumulator,(left,right)->new StringBuilder());
如果我通过NULL
然后返回N.P.E,则输出相同。
该参数用于什么?
更新
为什么如果我在parallelStream
上运行它,我会收到不同的结果?
首次运行。
returned StringBuilder length = 420
第二次运行
returned StringBuilder length = 546
第三次运行
returned StringBuilder length = 348
等等?为什么这个...不应该在每次迭代时返回所有值?
任何帮助都非常感激。
感谢。
答案 0 :(得分:14)
接口reduce
中的方法Stream
已超载。具有三个参数的方法的参数是:
combiner
支持并行执行。显然,它不用于顺序流。但是,没有这样的保证。如果您将流更改为并行流,我想您会看到不同之处:
Stream<String>stringStream = Stream.of(
"John Lennon", "Paul Mccartney", "George Harrison", "Ringo Starr")
.parallel();
以下是combiner
如何用于将顺序缩减转换为缩减的示例,该缩减支持并行执行。有一个包含四个String
s的流,acc
用作accumulator.apply
的缩写。然后,减少的结果可以如下计算:
acc(acc(acc(acc(identity, "one"), "two"), "three"), "four");
使用兼容的combiner
,上述表达式可以转换为以下表达式。现在可以在不同的线程中执行两个子表达式。
combiner.apply(
acc(acc(identity, "one"), "two"),
acc(acc(identity, "three"), "four"));
关于第二个问题,我使用简化的accumulator
来解释问题:
BiFunction<StringBuilder,String,StringBuilder> accumulator =
(builder,name) -> builder.append(name);
根据Stream::reduce的Javadoc,accumulator
必须是associative。在这种情况下,这意味着,以下两个表达式返回相同的结果:
acc(acc(acc(identity, "one"), "two"), "three")
acc(acc(identity, "one"), acc(acc(identity, "two"), "three"))
对于上述accumulator
,情况并非如此。问题是,您正在改变identity
引用的对象。这对于reduce
操作来说是个坏主意。以下是两个可行的替代实现:
// identity = ""
BiFunction<String,String,String> accumulator = String::concat;
// identity = null
BiFunction<StringBuilder,String,StringBuilder> accumulator =
(builder,name) -> builder == null
? new StringBulder(name) : builder.append(name);
答案 1 :(得分:3)
nosid's answer大部分都是正确的(+1),但我想扩大一个特定点。
identity
reduce
参数必须是身份值。没关系,如果它是一个对象,但如果它是,它应该是不可变的。如果“身份”对象发生变异,则不再是身份!有关这一点的更多讨论,请参阅my answer相关问题。
看起来这个例子起源于Richard Warburton的例子5-19, Java 8 Lambdas ,O'Reilly 2014.如果是这样,我将不得不与好博士谈谈这个问题。沃伯顿。