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;
    }
1
Virx 7 Сен 2016 в 11:53

3 ответа

Лучший ответ

BigDecimal неизменяем, поэтому ваш forEach вызывает add, но ничего не делает с результатом. reduce - в этом случае правильный оператор потока.

Если вы видите Добавление BigDecimals с помощью потоков. Вы должны использовать .reduce(BigDecimal.ZERO, BigDecimal::add), что сделает тело вашего цикла:

interest = i.getTransactions().stream()
                .map(Transaction::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
5
Community 23 Май 2017 в 10:29

Как объясняется в принятом ответе, 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);
}
1
Community 23 Май 2017 в 12:02

Поскольку BigDecimal неизменяемый, вызов add для него не изменит значение. Вместо этого он возвращает новый BigDecimal. forEach просто игнорирует любые возвращенные значения.

interest всегда сохраняет свое начальное значение BigDecimal.ZERO.

В отличие от этого reduce объединяет элементы с использованием заданного BinaryOperator. BigDecimal::add на самом деле является сокращенной формой для (a, b) -> a.add(b), и этот оператор будет применяться для объединения всех элементов потока.

4
fabian 7 Сен 2016 в 09:01