BigDecimal getInterest(List<Investment> investments) {
BigDecimal interest = BigDecimal.ZERO;
for (Investment i: investments) {
i.getTransactions().stream()
.map(Transaction::getAmount)
.forEach(interest::add);
}
return interest;
}
此方法的问题在于它始终返回零。看起来.forEach()
没有消耗它的论点。但是如果我按照下面的方式编写它,一切都运行正常。任何人都知道为什么第一种方法不起作用?
BigDecimal getInterest(List<Investment> investments) {
BigDecimal interest = BigDecimal.ZERO;
for (Investment i: investments) {
interestPaid = interest.add(i.getTransactions().stream()
.map(Transaction::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add));
}
return interest;
}
答案 0 :(得分:5)
BigDecimal
是不可变的,因此您的forEach
正在调用add
,但没有对结果做任何事情。在这种情况下,reduce
是正确的流运算符。
如果您看到Adding up BigDecimals using Streams。你应该使用.reduce(BigDecimal.ZERO, BigDecimal::add)
,这将使你的循环体:
interest = i.getTransactions().stream()
.map(Transaction::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
答案 1 :(得分:4)
由于BigDecimal
是不可变的,因此调用add
不会更改该值。它改为返回一个新的BigDecimal
。 forEach
只是忽略了返回的任何值。
interest
将始终保持BigDecimal.ZERO
的初始值。
与reduce
使用给定的BinaryOperator
组合元素相反。 BigDecimal::add
实际上是(a, b) -> a.add(b)
的简短形式,此运算符将用于合并所有流元素。
答案 2 :(得分:1)
正如accepted answer所解释的那样,BigDecimal.add
不会修改实例,但会返回一个新值,而您的第一个变体不使用结果。作为附录,如果您不在第二个变体中使用reduce
的结果,则会发生同样的情况,但是,您不仅要将结果传递给先前值add
的调用,您还需要将后续add
的结果分配给您的本地变量。
但值得注意的是,你的循环和流操作混合不一致。您可以将整个操作表示为单个Stream操作:
BigDecimal getInterest(List<Investment> investments) {
return investments.stream()
.flatMap(i -> i.getTransactions().stream())
.map(Transaction::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}