Java Lambda表达式避免多次迭代

lya*_*ffe 7 java lambda java-8 java-stream

伙计们,

考虑以下示例,给定一个Trade对象列表,我的代码需要返回一个包含交易量24小时,7天,30天和所有时间的数组.

使用普通的旧迭代器,这只需要对集合进行一次迭代.

我正在尝试使用Java 8流和Lambda表达式来做同样的事情.我提出了这个代码,它看起来很优雅,工作正常,但需要在列表上进行4次迭代:

public static final int DAY = 24 * 60 * 60;

public double[] getTradeVolumes(List<Trade> trades, int timeStamp) {
    double volume = trades.stream().mapToDouble(Trade::getVolume).sum();
    double volume30d = trades.stream().filter(trade -> trade.getTimestamp() + 30 * DAY > timeStamp).mapToDouble(Trade::getVolume).sum();
    double volume7d = trades.stream().filter(trade -> trade.getTimestamp() + 7 * DAY > timeStamp).mapToDouble(Trade::getVolume).sum();
    double volume24h = trades.stream().filter(trade -> trade.getTimestamp() + DAY > timeStamp).mapToDouble(Trade::getVolume).sum();
    return new double[]{volume24h, volume7d, volume30d, volume};
}
Run Code Online (Sandbox Code Playgroud)

如何在列表中仅使用一次迭代来实现相同的目标?

Bri*_*etz 9

此问题类似于"摘要统计信息"收集器.看看IntSummaryStatistics课程:

public class IntSummaryStatistics implements IntConsumer {
    private long count;
    private long sum;
    ...

    public void accept(int value) {
        ++count;
        sum += value;
        min = Math.min(min, value);
        max = Math.max(max, value);
   }

   ...
Run Code Online (Sandbox Code Playgroud)

}

它旨在与...一起工作collect(); 这是实施的IntStream.summaryStatistics()

public final IntSummaryStatistics summaryStatistics() {
    return collect(IntSummaryStatistics::new, IntSummaryStatistics::accept,
                   IntSummaryStatistics::combine);
}
Run Code Online (Sandbox Code Playgroud)

Collector这样的好处是你的自定义聚合可以并行运行.


dka*_*zel 0

可能可以使用一种Collectors.groupingBy方法来划分数据,但是方程会很复杂并且不具有意图揭示性。

由于getTimestamp()这是一项昂贵的操作,因此最好将其保留为 Java 8 之前的迭代,这样您只需为每个 计算一次值Trade

仅仅因为 Java 8 添加了闪亮的新工具,不要试图将其变成一把锤子来敲击所有钉子。