Estoy tratando de recrear un proceso para crear una lista de objetos que son una agregación de otra lista de objetos utilizando Java 8 corrientes.
por ejemplo, tengo una clase, se describe a continuación, que se proporciona desde una llamada base de datos o similares
public class Order {
private String orderNumber;
private String customerNumber;
private String customerGroup;
private Date deliveryDate;
private double orderValue;
private double orderQty;
}
En otra parte de mi aplicación tengo una clase que representa OrderTotal y agregación de la Orden agrupación por número de cliente y de grupo y sumando los totales de orderValue y OrderQty. (Con un código hash iguales y en customerGroup y CUSTOMERNUMBER)
public class OrderTotal {
private String customerGroup;
private String customerNumber;
private double totalValue;
private double totalQty;
}
La forma 'larga mano' que hemos logrado esto antes de java 8 es la siguiente
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());
}
He estado buscando en los colectores utilizando una agrupación de funciones y de reducción, pero todos ellos parecen centrado en la agregación de la clase para componer en lugar de los totales en la clase OrderTotal.
Busco una corriente ordenada o la función de cobro que elimina toda la hinchazón de este código.
Puede utilizar el toMap
colector de la siguiente manera:
Collection<OrderTotal> result = orders.stream()
.map(o -> createFromOrder(o))
.collect(toMap(Function.identity(),
Function.identity(),
(l, r) -> {
aggregate(l, r);
return l;
}))
.values();
Tenga en cuenta que esto requiere cambiar los aggregate
parámetros del método a aggregate(OrderTotal orderTotal, OrderTotal order){ ... }
, es decir, ambos parámetros son de tipo OrderTotal
.
o se puede quitar el aggregate
método completamente y realizar la lógica en el 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();