我正在尝试重新创建一个过程,以创建一个对象列表,该对象列表是使用Java 8 Streams的另一个对象列表的集合。
例如,我有一个如下所述的类,它是通过数据库调用或类似方法提供的
public class Order {
private String orderNumber;
private String customerNumber;
private String customerGroup;
private Date deliveryDate;
private double orderValue;
private double orderQty;
}
在我的应用程序的其他地方,我有一个OrderTotal类,该类表示和汇总按客户编号和组分组的Order分组,并汇总orderValue和orderQty的总数。 (在customerGroup和customerNumber上使用等于和哈希码)
public class OrderTotal {
private String customerGroup;
private String customerNumber;
private double totalValue;
private double totalQty;
}
我们在Java 8之前实现这一目标的“长手”方法如下
public Collection<OrderTotal> getTotals(List<Order> orders) {
///map created for quick access to the order total for each order
Map<OrderTotal, OrderTotal> map = new HashMap<>();
///loop through all orders adding to the relevaent order total per iteration
for (Order order : orders) {
OrderTotal orderTotal = createFromOrder(order);
{
///if the order total already exists in the map use that one, otherwise add it to the map.
OrderTotal temp = map.get(orderTotal);
if(temp == null){
map.put(orderTotal, orderTotal);
}else{
orderTotal = temp;
}
}
///add the values to the total
aggregate(orderTotal, order);
}
return map.values();
}
private OrderTotal createFromOrder(Order order) {
OrderTotal orderTotal = new OrderTotal();
orderTotal.setCustomerGroup(order.getCustomerGroup());
orderTotal.setCustomerNumber(order.getCustomerNumber());
return orderTotal;
}
private void aggregate(OrderTotal orderTotal, Order order){
orderTotal.setTotalQty(orderTotal.getTotalQty() + order.getOrderQty());
orderTotal.setTotalValue(orderTotal.getTotalValue() + order.getOrderValue());
}
我一直在使用分组和归约功能查看收集器,但它们似乎都集中在汇总订单类而不是在OrderTotal类中汇总总数。
我正在寻找一个整齐的流或收集功能,以消除此代码中的所有膨胀。
答案 0 :(得分:7)
您可以按如下方式使用toMap
收集器:
Collection<OrderTotal> result = orders.stream()
.map(o -> createFromOrder(o))
.collect(toMap(Function.identity(),
Function.identity(),
(l, r) -> {
aggregate(l, r);
return l;
}))
.values();
请注意,这需要将aggregate
方法参数更改为aggregate(OrderTotal orderTotal, OrderTotal order){ ... }
,即两个参数均为OrderTotal
类型。
或者您可以完全删除aggregate
方法并在toMap
中执行逻辑:
Collection<OrderTotal> result = orders.stream()
.map(o -> createFromOrder(o))
.collect(toMap(Function.identity(),
Function.identity(),
(l, r) -> {
l.setTotalQty(l.getTotalQty() + r.getTotalQty());
l.setTotalValue(l.getTotalValue() + r.getTotalValue());
return l;
}))
.values();
答案 1 :(得分:2)
您可以这样做-
Double totalQtyAgg = orders.stream()
.map(x -> createFromOrder(x))
.mapToDouble(x -> x.totalQty)
.sum();
Double totalValueAgg = orders.stream()
.map(x -> createFromOrder(x))
.mapToDouble(x -> x.totalValue)
.sum();