Lambda to collect properties in a child object I have a class:

public class ProductInvoice {
     //Some other properties.
    private List&lt;ProductEntry&gt; productEntries = newArrayList();
//otherMethods
}


And:

public class ProductEntry {
//other properties
    private Long quantity;
    private Long productId;
}


Now  I need to prepare a map of productId vs quantity by iterating over a collection of ProductInvoice objects:

List&lt;ProductInvoice&gt; entries = productInvoiceRepository.findByProductEntries_ProductIdIn(productIds);
        Map&lt;Long, Long&gt; productIdVsQuantity = newHashMap();
        entries.forEach( pi -&gt; pi.getProductEntries().forEach(pe -&gt; {
            if (productIdVsQuantity.containsKey(pe.getProductId())) {
                productIdVsQuantity.put(pe.getProductId(), productIdVsQuantity.get(pe.getProductId()) + pe.getQuantity());
            } else {
                productIdVsQuantity.put(pe.getProductId(), pe.getQuantity());
            }
        }));


Could there be a better way of doing this? I think this can be optimized using better lambda usage.
First, you can use Stream.flatMap() to convert a Stream of ProductInvoice to ProductEntries.

Next, you just need suitable Collector implementations to sum all the quantities per product ID, and group by that...

Putting it all together:

Map&lt;Long, Long&gt; result = productInvoiceRepository
                            .findByProductEntries_ProductIdIn(productIds)
                            .stream().flatMap(v -&gt; v.getProductEntries().stream())
                            .collect(Collectors.groupingBy(ProductEntry::getProductId,
                                    Collectors.summingLong(ProductEntry::getQuantity)));


BTW, you may want to consider a better method name for findByProductEntries_ProductIdIn() to remove the underscore...