javajava-8java-stream

Create a Map<Long, CustomObject> , iterating a List<CustomObject>


I've a list of Order which I am fetching from some third part api.

List<Order> orders = fromApi(orderId);

Here is the Order class:

class Order{
     Long orderId;
     Product product
}

Similarly I fetch products also for those orders. Here the key is orderId.

List<Order> orderIds = orders.stream().map(Order::orderId).collect(Collectors.toList());
Map<Long,Product> userProductMap = fromAnotherApi(orderIds);

Here is Product class:

class Product{
        String productDesc;
}

I want to extract a map with orderId as a key and Order as value(given below), but meanwhile also want to update orders with the product(from userProductMap) in same stream iteration.

 Map<Long,Order> userOrderMap = orders.stream().collect(Collectors.toMap(order -> order.id, Function.identity()));

I want to provide some custom implementation instead of Function.identity() so that while putting Order as value in Map here, I take out product from the userProductMap and update in Order and use updated Order in Map as value.


Solution

  • I’m not sure Streams are beneficial here, since you are modifying each Order as you add it to a Map. I would just use a loop:

    Map<Long, Order> ordersById = new HashMap<>();
    for (Order order : orders) {
        Long orderId = order.getOrderId();
        order.setProduct(userProductMap.get(orderId));
        ordersById.put(orderId, order);
    }
    

    If you insist on doing it with a Stream, and if you have the ability to modify the Order class, you can add a chaining method that returns the object itself:

    public class Order {
        // [other fields and methods]
    
        public Order withProduct(Product product) {
            this.product = product;
            return this;
        }
    }
    

    which allows you to write this:

    Map<Long, Order> ordersById = orders.stream()
        .collect(Collectors.toMap(o -> o.getOrderId(),
            o -> o.withProduct(userProductMap.get(o.getOrderId()))));
    

    If you don’t have the ability to modify the Order class, but still insist on using a Stream, you probably need to fall back to using the peek method:

    Map<Long, Order> ordersById = orders.stream()
        .peek(o -> o.setProduct(userProductMap.get(o.getOrderId())))
        .collect(Collectors.toMap(o -> o.getOrderId(), o -> o));
    

    This isn’t really what peek is for, so I personally would opt for one of the other approaches.