使用Java 8 Streams映射,汇总和组合总计

use*_*416 7 java composition aggregation java-8 java-stream

我正在尝试重新创建一个过程,以创建一个对象列表,该对象列表是使用Java 8 Streams的另一个对象列表的集合。

例如,我有一个如下所述的类,它是通过数据库调用或类似方法提供的

public class Order {

    private String orderNumber;        
    private String customerNumber;
    private String customerGroup;
    private Date deliveryDate;
    private double orderValue;
    private double orderQty;
}
Run Code Online (Sandbox Code Playgroud)

在我的应用程序的其他地方,我有一个OrderTotal类,该类代表和汇总按客户编号和组分组的Order分组,并汇总orderValue和orderQty的总数。(在customerGroup和customerNumber上使用等于和哈希码)

public class OrderTotal {

    private String customerGroup;
    private String customerNumber;
    private double totalValue;
    private double totalQty;
}
Run Code Online (Sandbox Code Playgroud)

我们在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());
}
Run Code Online (Sandbox Code Playgroud)

我一直在使用分组和归约函数查看收集器,但它们似乎都集中在汇总订单类而不是在OrderTotal类中汇总总数。

我正在寻找一个整洁的流或收集功能,以消除此代码中的所有膨胀。

Ous*_* D. 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();
Run Code Online (Sandbox Code Playgroud)

请注意,这需要将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();
Run Code Online (Sandbox Code Playgroud)