2016-03-07 5 views
0

У меня небольшая проблема с лямбдами. Как я могу перебирать его и добавлять значение каждой итерации к моей переменной currentLateAmountDouble?Java 8 лямбда-агрегат

BigDecimal currentLateAmountDouble = BigDecimal.ZERO; 
Collection<VPO> lines = BO_Contract.getLines(trxName, contractVPO.getID(), RContractLine.LineNo + " ASC ", ctx); 
if (lines != null && !lines.isEmpty()) { 
    if (lines.stream() 
      .filter(line -> onDate.compareTo(line.getDateValue(RContractLine.TermDate)) > 0) != null) { 
     lines.forEach(line -> currentLateAmountDouble = currentLateAmountDouble.add(NumberUtils.getAmount(line.getDoubleValue(RContractLine.TotalAmountOpen)))); 
    } 
} 

Это дает мне ошибку на 5-й линии:

Локальная переменная currentLateAmountDouble определена в области видимости должно быть окончательным или эффективно окончательным

Тот же метод в Java 7 (работ):

BigDecimal currentLateAmountDouble = BigDecimal.ZERO; 
Collection<VPO> lines = BO_Contract.getLines(trxName, contractVPO.getID(), RContractLine.LineNo + " ASC ", ctx); 
if (lines != null && !lines.isEmpty()) { 
    for (VPO line : lines) { 
     if (onDate.compareTo(line.getDateValue(RContractLine.TermDate)) > 0) { 
      currentLateAmountDouble = currentLateAmountDouble.add(NumberUtils.getAmount(line.getDoubleValue(RContractLine.TotalAmountOpen))); 
     } 
    } 
} 

EDI Т: Решен! Ходили с раствором @JBNizet и сделал это так:

currentLateAmountDouble = lines.stream().filter(line -> onDate.compareTo(line.getDateValue(RContractLine.TermDate)) > 0) 
       .map(line -> NumberUtils.getAmount(line.getDoubleValue(RContractLine.TotalAmountOpen))).reduce(BigDecimal.ZERO, BigDecimal::add); 

ответ

2

Как сказано в сообщении об ошибке, вы не можете переназначить внешнюю локальную переменную с лямбда (так же, как от анонимного класса в Java 7).

Попытка изменить внешнее состояние из функциональных операций - это запах кода. Но ваша работа только отображение, а затем с помощью операции восстановления: вы transformaing каждого элемента к BigDecimal, а затем просуммировать все BigDecimals:

BigDecimal currentLateAmountDouble = 
    lines.stream() 
     .map(line -> NumberUtils.getAmount(line.getDoubleValue(RContractLine.TotalAmountOpen))) 
     .reduce(BigDecimal.ZERO, BigDecimal::add); 

Обратите внимание, что ваш тест, который сравнивает результат filter() с нулем не имеет смысла: filter() никогда, никогда не вернется null. Вероятно, вы ищете anyMatch.

1

Вы должны использовать функцию уменьшения ...

попробовать это в вашем заявлении, если ...

currentLateAmountDouble = lines.stream().mapToInt(l->NumberUtils.getAmount(l.getDoubleValue(RContractLine.TotalAmountOpen)).sum(); 

не может быть точным, я не на компьютере, чтобы проверить это но должен быть достаточно близко.

также, см. https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html для справки