各位,
考虑以下示例,给定一个 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};
}
我怎样才能只对列表进行一次迭代来实现同样的效果?
最佳答案
这个问题类似于“汇总统计”收集器。看一下 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);
}
...
它设计用于与 collect()
一起工作;这是 IntStream.summaryStatistics()
public final IntSummaryStatistics summaryStatistics() {
return collect(IntSummaryStatistics::new, IntSummaryStatistics::accept,
IntSummaryStatistics::combine);
}
像这样编写 Collector
的好处是您的自定义聚合可以并行运行。
关于避免多次迭代的 Java Lambda 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24407931/