我想采用以下方法:

public BigDecimal mean(List<BigDecimal> bigDecimals, RoundingMode roundingMode) {
    BigDecimal sum = BigDecimal.ZERO;
    int count=0;
    for(BigDecimal bigDecimal : bigDecimals) {
        if(null != bigDecimal) {
            sum = sum.add(bigDecimal);
            count++;
        }
    }
    return sum.divide(new BigDecimal(count), roundingMode);
}

并使用Streams API对其进行更新。到目前为止,这是我得到的:
public BigDecimal average(List<BigDecimal> bigDecimals, RoundingMode roundingMode) {
    BigDecimal sum = bigDecimals.stream()
        .map(Objects::requireNonNull)
        .reduce(BigDecimal.ZERO, BigDecimal::add);
    long count = bigDecimals.stream().filter(Objects::nonNull).count();
    return sum.divide(new BigDecimal(count), roundingMode);
}

有没有办法避免两次流式传输(第二次获得计数)吗?

最佳答案

BigDecimal[] totalWithCount
                = bigDecimals.stream()
                .filter(bd -> bd != null)
                .map(bd -> new BigDecimal[]{bd, BigDecimal.ONE})
                .reduce((a, b) -> new BigDecimal[]{a[0].add(b[0]), a[1].add(BigDecimal.ONE)})
                .get();
BigDecimal mean = totalWithCount[0].divide(totalWithCount[1], roundingMode);

对于那些认为有帮助的代码的可选文本描述(如果发现代码足以说明问题,请忽略。):
  • BigDecimals的列表将转换为流。
  • 空值从流中过滤掉。
  • BigDecimals的流映射为BigDecimal的两个元素数组的流,其中第一个元素是原始流中的元素,第二个元素是值为1的占位符。
  • 在减少中,a(a,b)值在第一个元素中具有部分和,在第二个元素中具有部分计数。 b元素的第一个元素包含要添加到总和的每个BigDecimal值。不使用b的第二个元素。
  • Reduce返回一个可选参数,如果列表为空或仅包含空值,则该参数将为空。
  • 如果Optional不为空,则Optional.get()函数将返回BigDecimal的两个元素数组,其中BigDecimals的总和在第一个元素中,而BigDecimals的计数在第二个元素中。
  • 如果Optional为空,则将引发NoSuchElementException。
  • 通过将总和除以计数来计算平均值。
  • 09-25 19:27