You can use mapToDouble and sum instead of forEach with Java Streams:
@Test
public void sumOfDoubleWithStreams()
{
List<Amount> numbers =
Arrays.asList(new Amount(10.0, 0.0), new Amount(20.0, 0.05), new Amount(30.0, 0.1));
double sum = numbers.stream()
.mapToDouble(
amount -> amount.hasInterest() ? amount.getAmountWithInterest() : amount.getAmount())
.sum();
Assert.assertEquals(64.0d, sum, 0.0d);
}
If you really want to use forEach, you need to have an object that can be mutated inside of the forEach call. You can use AtomicDouble here, or another class like DoubleSummaryStatistics or your own accumulating class.
@Test
public void sumOfDoubleWithForEach()
{
List<Amount> numbers =
Arrays.asList(new Amount(10.0, 0.0), new Amount(20.0, 0.05), new Amount(30.0, 0.1));
AtomicDouble sum = new AtomicDouble();
numbers.forEach(amount ->
sum.addAndGet(amount.hasInterest() ? amount.getAmountWithInterest() : amount.getAmount()));
Assert.assertEquals(64.0d, sum.get(), 0.0d);
}
If you are open to using a third-party library, you can use sumOfDouble on any container from Eclipse Collections.
@Test
public void sumOfDouble()
{
MutableList<Amount> numbers =
Lists.mutable.with(new Amount(10.0, 0.0), new Amount(20.0, 0.05), new Amount(30.0, 0.1));
double sum = numbers.sumOfDouble(
amount -> amount.hasInterest() ? amount.getAmountWithInterest() : amount.getAmount());
Assert.assertEquals(64.0d, sum, 0.0d);
}
I created an Amount class to hold the amount and interest rate:
public static final class Amount
{
private final double amount;
private final double interest;
public Amount(double amount, double interest)
{
this.amount = amount;
this.interest = interest;
}
public double getAmountWithInterest()
{
return this.amount * (1.0 + this.interest);
}
public boolean hasInterest()
{
return this.interest > 0.0d;
}
public double getAmount()
{
return amount;
}
}
Note: I am a committer for Eclipse Collections.