我正在为新手程序员编写一个库,所以我试图保持API尽可能干净.
我的库需要做的一件事就是对大量的int或long进行一些复杂的计算.我的用户需要从中计算这些值所需的大量场景和业务对象,因此我认为最好的方法是使用流来允许用户将业务对象映射到IntStream
或者LongStream
然后计算收集器内的计算.
但是IntStream和LongStream只有3参数collect方法:
collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner)
Run Code Online (Sandbox Code Playgroud)
而且没有简单的collect(Collector)
方法Stream<T>
.
所以不是能够做到的
Collection<T> businessObjs = ...
MyResult result = businessObjs.stream()
.mapToInt( ... )
.collect( new MyComplexComputation(...));
Run Code Online (Sandbox Code Playgroud)
我必须提供像这样的供应商,蓄电池和组合器:
MyResult result = businessObjs.stream()
.mapToInt( ... )
.collect(
()-> new MyComplexComputationBuilder(...),
(builder, v)-> builder.add(v),
(a,b)-> a.merge(b))
.build(); //prev collect returns Builder object
Run Code Online (Sandbox Code Playgroud)
对于我的新手用户来说这太复杂了,而且非常容易出错.
我的工作是创建一个静态方法,它接受IntStream
或LongStream
作为输入,并为您隐藏收集器的创建和执行
public static MyResult compute(IntStream stream, ...){
return .collect(
()-> new MyComplexComputationBuilder(...),
(builder, v)-> builder.add(v),
(a,b)-> a.merge(b))
.build();
} …
Run Code Online (Sandbox Code Playgroud) Java API文档声明combiner
该collect
方法的参数必须是:
用于组合两个值的关联,非干扰,无状态函数,它必须与累加器函数兼容
A combiner
是BiConsumer<R,R>
接收两个类型的参数R
并返回void
.但是文档没有说明我们是否应该将元素组合到第一个或第二个参数中?
例如,以下示例可以给出不同的结果,取决于组合的顺序是: m1.addAll(m2)
或m2.addAll(m1)
.
List<String> res = LongStream
.rangeClosed(1, 1_000_000)
.parallel()
.mapToObj(n -> "" + n)
.collect(ArrayList::new, ArrayList::add,(m1, m2) -> m1.addAll(m2));
Run Code Online (Sandbox Code Playgroud)
我知道在这种情况下我们可以简单地使用方法句柄,例如ArrayList::addAll
.然而,在某些情况下需要Lambda并且我们必须以正确的顺序组合项目,否则我们可能在并行处理时得到不一致的结果.
这是否在Java 8 API文档的任何部分中声明了?或者它真的没关系?