I'm trying to solve the problem described in the following question using collector reducing()
:
Creating Map of Maps using a custom Object as a reduction type in Java 8
We need to obtain a Map<String,Map<String,MySumObject>>
as a result by adding up BigDecimal
amounts of loan objects represented by MyObject
while grouping the data by loanType
then loanCurrency
.
Dummy classes:
class MyObject {
String loanType;
String loanCurrency;
BigDecimal amountPaid;
BigDecimal amountRemaining;
}
class MySumObject {
BigDecimal paidSum;
BigDecimal remainingSum;
}
Based on Alexander Ivanchenko's solution (see the link to original question) using
Collector.of(
MySumObject::new,
MySumObject::addLoan,
MySumObject::merge
)
Firstly, I've changed it in the following way:
list.stream().collect(groupingBy(MyObject::getLoanType,
groupingBy(MyObject::getLoanCurrency,
Collector.of(
MySumObject::new,
(mySumObject, myObject) -> {
mySumObject.setPaidSum(mySumObject.getPaidSum().add(myObject.getAmountPaid()));
mySumObject.setRemainingSum(mySumObject.getRemainingSum().add(myObject.getAmountRemaining()));
},
(mySumObject1, mySumObject2) -> {
mySumObject1.setPaidSum(mySumObject1.getPaidSum().add(mySumObject2.getPaidSum()));
mySumObject1.setRemainingSum(mySumObject1.getRemainingSum().add(mySumObject2.getRemainingSum()));
return mySumObject1;
})
)
));
Then I was trying to make it working using collector reducing()
.
But it appears that it adds up everything together regardless of groupingBy()
. Not sure which part is wrong:
List<MyObject> list = List.of(
new MyObject("Type1", "Currency1", BigDecimal.valueOf(10), BigDecimal.valueOf(100)),
new MyObject("Type1", "Currency1", BigDecimal.valueOf(10), BigDecimal.valueOf(100)),
new MyObject("Type2", "Currency2", BigDecimal.valueOf(20), BigDecimal.valueOf(200)),
new MyObject("Type3", "Currency3", BigDecimal.valueOf(30), BigDecimal.valueOf(300)),
new MyObject("Type4", "Currency4", BigDecimal.valueOf(40), BigDecimal.valueOf(400))
);
list.stream().collect(groupingBy(MyObject::getLoanType,
groupingBy(MyObject::getLoanCurrency,
reducing(new MySumObject(BigDecimal.ZERO,BigDecimal.ZERO),
(myObject) -> new MySumObject(
myObject.getAmountPaid(),
myObject.getAmountRemaining()
),
(mySumObject1, mySumObject2) -> {
mySumObject1.setPaidSum(mySumObject1.getPaidSum().add(mySumObject2.getPaidSum()));
mySumObject1.setRemainingSum(mySumObject1.getRemainingSum().add(mySumObject2.getRemainingSum()));
return mySumObject1;
})
)
));
Here is the output it produces. All the values are added together, which is incorrect.
Type2={Currency2=MySumObject(paidSum=110, remainingSum=1100)}
Type3={Currency3=MySumObject(paidSum=110, remainingSum=1100)}
Type4={Currency4=MySumObject(paidSum=110, remainingSum=1100)}
Type1={Currency1=MySumObject(paidSum=110, remainingSum=1100)}