【发布时间】:2016-10-26 19:00:26
【问题描述】:
我正在编写一个自定义的 java 8 收集器,它应该计算具有 getValue() 方法的 POJO 的平均值。代码如下:
public static Collector<BoltAggregationData, BigDecimal[], BigDecimal> avgCollector = new Collector<BoltAggregationData, BigDecimal[], BigDecimal>() {
@Override
public Supplier<BigDecimal[]> supplier() {
return () -> {
BigDecimal[] start = new BigDecimal[2];
start[0] = BigDecimal.ZERO;
start[1] = BigDecimal.ZERO;
return start;
};
}
@Override
public BiConsumer<BigDecimal[], BoltAggregationData> accumulator() {
return (a,b) -> {
a[0] = a[0].add(b.getValue());
a[1] = a[1].add(BigDecimal.ONE);
};
}
@Override
public BinaryOperator<BigDecimal[]> combiner() {
return (a,b) -> {
a[0] = a[0].add(b[0]);
a[1] = a[1].add(b[1]);
return a;
};
}
@Override
public Function<BigDecimal[], BigDecimal> finisher() {
return (a) -> {
return a[0].divide(a[1], 6 , RoundingMode.HALF_UP);
};
}
private final Set<Characteristics> CHARACTERISTICS = new HashSet<Characteristics>(Arrays.asList(Characteristics.CONCURRENT, Characteristics.UNORDERED));
@Override
public Set<Characteristics> characteristics() {
return CHARACTERISTICS;
}
};
在非并行情况下一切正常。但是,当我使用parallelStream() 时,它有时不起作用。例如,给定从 1 到 10 的值,它会计算(53/9 而不是 55/10)。调试时,调试器永远不会命中 combiner() 函数中的断点。我需要设置某种标志吗?
【问题讨论】:
-
我确实对两者都投了赞成票,也感谢您的回答:) 我只是发现另一个答案更清楚了。也感谢 EnumSet 的提示。
-
没关系,我只是注意到您在短时间内接受(或试图接受)两者,所以我只是想消除潜在的混淆。
-
请注意,有更好的方法可以做到这一点,例如cumulative moving average。
-
附带说明,如果您以任何方式使用匿名类,您仍然可以使用
Collector.of缩小代码大小... -
如果我们有其他改进代码的方法,可以使用数组初始化器:
BigDecimal[] start = { BigDecimal.ZERO, BigDecimal.ZERO }; return start;或() -> new BigDecimal[] { BigDecimal.ZERO, BigDecimal.ZERO },使用… -> expression形式,这也适用于整理器:a -> a[0].divide(a[1], 6 , RoundingMode.HALF_UP)。
标签: java java-8 java-stream collectors