Reputation: 33
I have a use case need to sum different feilds in this object so I code like this, can I put it in one stream?
int totalUnits = records.stream()
.mapToInt(DynamoSalesAggregateSummaryRecord::getUnits).sum();
int totalReturns = records.stream()
.mapToInt(DynamoSalesAggregateSummaryRecord::getReturns).sum();
int totalCancellations = records.stream()
.mapToInt(DynamoSalesAggregateSummaryRecord::getCancellations).sum();
BigDecimal totalRevenue = records.stream()
.map(DynamoSalesAggregateSummaryRecord::getRevenue)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal totalRoyalties = records.stream()
.map(DynamoSalesAggregateSummaryRecord::getRoyalties)
.reduce(BigDecimal.ZERO, BigDecimal::add);
Upvotes: 1
Views: 168
Reputation: 140427
Honestly, I would not do that. Instead: get rid of the code duplication in the first place: write a little helper that invokes:
return records.stream().mapToInt(accessorMethod).sum();
(where you pass the accessor to that method).
Then you could go for:
int totals = fetch(DynamoSalesAggregateSummaryRecord::getUnits) + fetch(DynamoSalesAggregateSummaryRecord::getReturns) + ...
But beyond that - it is actually not clear what you intend to do here. The above example assumed that you would build a "total" sum of all entries. If that is the not the case - and you want "distinct" sums, my advise would be to give up on using mapToInt()
. And instead do something like:
class SumHelper {
private int unitTotals = 0;
private int returnTotals = 0;
...
public add(DynamoSalesAggregateSummaryRecord record) {
unitTotals += record.getUnits();
...
to be used like:
SumHelper helper = new SumHelper;
records.forEach(r -> helper.add(r));
In other words: you want to call multiple different methods on a record; to build different sums. You can't do that with streams - as one operation is creating multiple results. So you need some other kind of "storage" to keep track of the different results.
Upvotes: 5
Reputation: 1896
Another approach would be to create a separate method getTotalSum
either in DynamoSalesAggregateSummaryRecord
class or (better) - external helper. That method sums up all required fields of a single DynamoSalesAggregateSummaryRecord
instance, then just sum it up:
int totalSum =
records.stream()
.mapToInt(DynamoSalesAggregateSummaryRecord::getTotalSum).sum()
Upvotes: 2
Reputation: 131336
java.util.stream.IntStream.sum()
is a terminal operation.
You cannot invoke another stream task after a terminal operation.
If you don't have lot of elements in the collection, the GhostCat solution is fine.
If it is not the case, to avoid iterating 5 times on the records
collection, another approach should be used.
You could use streams to do it but I am not sure that you will gain in readability as you should probably write your own code to compute aggregates.
A classic loop seems fine in this context :
int totalUnits = 0;
int totalReturns = 0;
...
for (DynamoSalesAggregateSummaryRecord record : records){
totalUnits += record.getUnits();
totalReturns += record.getReturns();
...
}
Upvotes: 1