【发布时间】:2015-07-30 09:40:28
【问题描述】:
我正在为新手程序员编写一个库,因此我试图让 API 尽可能干净。
我的库需要做的一件事是对大量 int 或 long 集合执行一些复杂的计算。我的用户需要从中计算这些值的场景和业务对象有很多,所以我认为最好的方法是使用流来允许用户将业务对象映射到 IntStream 或 LongStream,然后计算里面的计算的收藏家。
但是 IntStream 和 LongStream 只有 3 个参数的 collect 方法:
collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner)
并且没有Stream<T> 拥有的更简单的collect(Collector) 方法。
所以不是能够做到
Collection<T> businessObjs = ...
MyResult result = businessObjs.stream()
.mapToInt( ... )
.collect( new MyComplexComputation(...));
我必须像这样提供供应商、累加器和组合器:
MyResult result = businessObjs.stream()
.mapToInt( ... )
.collect(
()-> new MyComplexComputationBuilder(...),
(builder, v)-> builder.add(v),
(a,b)-> a.merge(b))
.build(); //prev collect returns Builder object
这对我的新手用户来说太复杂了,而且很容易出错。
我的工作是制作以IntStream 或LongStream 作为输入的静态方法,并为您隐藏收集器的创建和执行
public static MyResult compute(IntStream stream, ...){
return .collect(
()-> new MyComplexComputationBuilder(...),
(builder, v)-> builder.add(v),
(a,b)-> a.merge(b))
.build();
}
但这不符合使用 Streams 的常规约定:
IntStream tmpStream = businessObjs.stream()
.mapToInt( ... );
MyResult result = MyUtil.compute(tmpStream, ...);
因为您必须保存一个临时变量并将其传递给静态方法,或者在静态调用中创建 Stream,当它与我的计算的其他参数混合时可能会造成混淆。
在使用IntStream 或LongStream 的同时,是否有更简洁的方法来执行此操作?
【问题讨论】:
-
不幸的是,我的建议是使用
Stream<Integer>。您可以通过mapToObj(Function.identity())从IntStream获取它。 -
如果编译器可以内联从转换到消费者的代码路径,它可能能够消除装箱/拆箱。只需像使用
IntStream一样使用基于 int 的接口编写它们,看看它是否会产生任何垃圾。 -
@DmitryGinzburg,
IntStream#boxed()提供相同的功能。 -
好吧,我们也不应该对编译器优化抱有太大的信心。
-
对你有好处。对我来说,它主要是基于信仰的——我相信我可以这样写,因为编译器可以优化它;我相信我不应该那样做,因为编译器不太可能优化它。 - 我懒得去测试实施策略的每一个排列。
标签: java java-8 java-stream api-design