[英]Using reducing in java
这是原始问题:
使用自定义 Object 作为 Java 中的缩减类型创建地图的 Map
它需要获取一个 Map<String,Map<String, MySumObject>> 来将金额相加,同时先按 LoanType 然后按 LoanCurrency 分组。
class MyObject {
String loanType;
String loanCurrency;
BigDecimal amountPaid;
BigDecimal amountRemaining;
}
class MySumObject {
BigDecimal paidSum;
BigDecimal remainingSum;
}
基于 Alexander Ivanchenko 的解决方案,使用
Collector.of(
MySumObject::new,
MySumObject::addLoan,
MySumObject::merge
)
我得到了下面的代码
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;
}
)
)
));
然后我想用减少来让它工作。但不管groupingBy如何,它都会把所有东西都加起来。 不知道哪一部分是错的。
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;
}
)
)
));
这是不正确的 output。
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)}
操作reduce()
意味着通过对不可变对象执行归约来折叠 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ(收集器归约reducing()
)也是如此)。 另一方面, collect()
操作用于执行可变归约。
将这两种方法混合在一起引起的观察 - 你正在改变身份而不是返回一个新的 object 。 那不是function应该如何减少。
因此,嵌套 Map 的所有条目都将持有对相同值的引用。 那将提供一个MySumObject
的实例作为归约的标识。 提醒: reduction reducing()
作为U
类型的第一个参数标识(不是Supplier
),因此只会创建一个标识object (您可以从构造函数打印一条消息以确保它只会被触发一次)。
为了应用收集器 reduction reducing()
来解决这个问题,您需要更改归约逻辑而不是改变身份,归约的每一步都应该产生一个新的MySumObject
。
为此,我们需要更改 reduction reducing()
的第三个参数,即BinaryOperator<U>
用于组合MySumObject
的两个实例。
在MyObject
class 中引入映射器方法会更方便。
旁注:尝试使用更有意义的名称。 它使使用代码更容易。 例如, Loan
代替MyObject
, LoanSum
代替MySumObject
。
这就是它的实现方式:
Map<String, Map<String, MySumObject>> result = list1.stream().collect(
Collectors.groupingBy(
MyObject::getLoanType,
Collectors.groupingBy(
MyObject::getLoanCurrency,
Collectors.reducing(
new MySumObject(),
MyObject::toMySum,
MySumObject::merge
))
));
MySumObject
class 与merge()
方法返回一个新的 object:
public static class MySumObject {
private BigDecimal paidSum = BigDecimal.ZERO;
private BigDecimal remainingSum = BigDecimal.ZERO;
public void addLoan(MyObject loan) {
paidSum = paidSum.add(loan.getAmountPaid());
remainingSum = remainingSum.add(loan.getAmountRemaining());
}
public MySumObject merge(MySumObject other) {
BigDecimal newPaidSum = paidSum.add(other.getPaidSum());
BigDecimal newRemainingSum = remainingSum.add(other.getRemainingSum());
return new MySumObject(newPaidSum, newRemainingSum);
}
// AllArgs & NoArgs constructors, getters, etc.
}
MyObject
class 与映射方法toMySum()
:
public static class MyObject {
private String loanType;
private String loanCurrency;
private BigDecimal amountPaid;
private BigDecimal amountRemaining;
public MySumObject toMySum() {
return new MySumObject(this.amountPaid, this.amountRemaining);
}
// constructor, getters, etc.
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.