【发布时间】:2022-11-12 10:26:48
【问题描述】:
Collector 具有三种通用类型:
public interface Collector<T, A, R>
以A 为归约操作的可变累积类型(通常作为实现细节隐藏).
如果我想创建我的自定义收集器,我需要创建两个类:
- 一种用于自定义累积类型
- 一个用于自定义收集器本身
是否有任何库函数/技巧可以采用累积类型并提供相应的收集器?
简单的例子
这个例子更简单地说明了这个问题,我知道我可以在这种情况下使用reduce,但这不是我想要的.这是more complex example,在这里分享会使问题变得太长,但这是相同的想法。
假设我想收集流的总和并将其作为String 返回。
我可以实现我的累加器类:
public static class SumCollector {
Integer value;
public SumCollector(Integer value) {
this.value = value;
}
public static SumCollector supply() {
return new SumCollector(0);
}
public void accumulate(Integer next) {
value += next;
}
public SumCollector combine(SumCollector other) {
return new SumCollector(value + other.value);
}
public String finish(){
return Integer.toString(value);
}
}
然后我可以从这个类创建一个Collector:
Collector.of(SumCollector::supply, SumCollector::accumulate, SumCollector::combine, SumCollector::finish);
但是对我来说似乎很奇怪,它们都指的是另一个类,我觉得有一种更直接的方法可以做到这一点。
为了只保留一个类,我可以做的是implements Collector<Integer, SumCollector, String>,但随后每个函数都会被复制(supplier() 将返回SumCollector::supply,等等)。
【问题讨论】:
-
我认为你总是需要两节课。一个永远是累加器对象。还有一个将实现
Collector接口。但是累加器对象没有包含所有supply()、combine()和finish()方法。它们仅在实现Collector的类中可用。持有者类也可能是收集器中的私有内部class。同样对于您的示例,您可以只使用AtomicInteger作为累加器。为您留下一个必须实现的类SumCollector implements Collector<Integer, AtomicInteger, String> -
“持有者类也可能是收集器中的私有内部类。” => 我不认为我可以像
implements Collector<Integer, SumCollector.Acc, String>那样做,我得到SumCollector.Acc' has private access in 'SumCollector'。 -
哦,是的,那么可悲的是它一定是
public。你也可以颠倒整个类结构。使Collector成为累加器的私有内部类。然后仅使用静态方法公开它:public static Collector<Integer, ?, String> collector() {return new SumCollector();}
标签: java java-stream collectors accumulate