我有一个 List<LedgerEntry> ledgerEntries
我需要计算 creditAmount 和 debitAmount 的总和。
class LedgerEntry{
private BigDecimal creditAmount;
private BigDecimal debitAmount;
//getters and setters
}
我已经实现了这个,
BigDecimal creditTotal = ledgeredEntries.stream().map(p ->p.getCreditAmount()).
reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal debitTotal = ledgeredEntries.stream().map(p ->p.getDebitAmount()).
reduce(BigDecimal.ZERO, BigDecimal::add);
//...
//Use creditTotal, debitTotal later
这看起来我正在遍历列表两次。有没有一种方法可以一次性完成这项工作,而不必两次处理 list ?
Java 8 之前的版本
BigDecimal creditTotal = BigDecimal.ZERO;
BigDecimal debitTotal = BigDecimal.ZERO;
for(LedgerEntry entry : ledgerEntries){
creditTotal = creditTotal.add(entry.getCreditAmount());
debitTotal = debitTotal.add(entry.getDebitAmount());
}
最佳答案
您可以减少到总计条目:
LedgerEntry totalsEntry = entries.stream().reduce(new LedgerEntry(), (te, e) -> {
te.setCreditAmount(te.getCreditAmount().add(e.getCreditAmount()));
te.setDebitAmount(te.getDebitAmount().add(e.getDebitAmount()));
return te;
});
更新
在评论中正确地指出 reduce()
不应该修改初始标识符值,并且 collect()
应该用于可变归约。下面是一个使用 collect()
的版本(使用相同的 BiConsumer
作为累加器和组合器)。如果未设置 creditAmount
和/或 debitAmount
值,它还解决了潜在 NPE 的问题。
BiConsumer<LedgerEntry, LedgerEntry> ac = (e1, e2) -> {
BigDecimal creditAmount = e1.getCreditAmount() != null ? e1.getCreditAmount() : BigDecimal.ZERO;
BigDecimal debitAmount = e1.getDebitAmount() != null ? e1.getDebitAmount() : BigDecimal.ZERO;
e1.setCreditAmount(creditAmount.add(e2.getCreditAmount()));
e1.setDebitAmount(debitAmount.add(e2.getDebitAmount()));
};
LedgerEntry totalsEntry = entries.stream().collect(LedgerEntry::new, ac, ac);
突然之间,Java 8 之前的版本开始变得极具吸引力。
关于Java 8 在一次迭代中求和两个对象属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42386191/