流不在for循环中工作

时间:2016-09-07 08:53:12

标签: java lambda java-8 java-stream

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;
    }

3 个答案:

答案 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不会更改该值。它改为返回一个新的BigDecimalforEach只是忽略了返回的任何值。

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);
}