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.