Reputation: 288
I'm having a small problem with lambdas. How can I iterate through it and add value every iteration to my variable currentLateAmountDouble?
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))));
}
}
It gives me an error on the 5th line:
Local variable currentLateAmountDouble defined in an enclosing scope must be final or effectively final
The same method in Java 7 (works):
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)));
}
}
}
EDIT: Solved! Went with @JBNizet solution and did it like this:
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);
Upvotes: 0
Views: 644
Reputation: 691775
As the error message says, you may not reassign an external local variable from a lambda (just as from an anonymous class, in Java 7).
Trying to modify an external state from functional operations is a code smell. But your operation is just a mapping, followed by a reduction operation: you're transformaing each element to a BigDecimal, and then sum all the BigDecimals:
BigDecimal currentLateAmountDouble =
lines.stream()
.map(line -> NumberUtils.getAmount(line.getDoubleValue(RContractLine.TotalAmountOpen)))
.reduce(BigDecimal.ZERO, BigDecimal::add);
Note that your test that compares the result of filter()
with null doesn't make sense: filter()
will never, ever return null. You're probably looking for anyMatch
here.
Upvotes: 3
Reputation: 245
You need to use a reducing function...
try this in your if statement...
currentLateAmountDouble = lines.stream().mapToInt(l->NumberUtils.getAmount(l.getDoubleValue( RContractLine.TotalAmountOpen)).sum();
it may not be exact, i'm not by a computer to test this out, but should get you close enough.
also, see https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html for reference
Upvotes: 1