Skip to content
Home » How to Map and Reduce Items From a List in Java

How to Map and Reduce Items From a List in Java

railways beside red building

Mapping items from a List means that each item from that List will be converted into another object.

Reducing items from a List means that all items from that List will be combined into a single object, which doesn’t necessarily have the same type as the original ones.

Let’s say we have a List of Orders and each order has a List of Products.

record Order(String customer, List<Product> products) {
}

record Product(String brand, String modelName, BigDecimal price) {
}

What would you do if you had to find out how much money comes from a List of orders?

For each Order, you’d have to get their Product list, and for each Product in those lists, you’d have to get their prices. After that, you’d have to sum all those prices, and finally, you would have the result.

Translating the above to Map/Reduce, you would have to:

  • Map each Order to its Product list
  • Map each Product to its price
  • Reduce all the prices by summing them with each other

So, let’s do it in Java:

public class OrderMapReducer {
    public BigDecimal getTotal(List<Order> orders) {
        return orders.stream() // 1
                     .map(Order::products) // 2
                     .flatMap(List::stream) // 3
                     .map(Product::price) // 4
                     .reduce(BigDecimal::add) // 5
                     .orElse(BigDecimal.ZERO); // 6
    }
}
  1. Creates a Stream of Orders
  2. Maps each Order to its product List
  3. Maps each List of Products to a Stream. Note that here we had to use flatMap, otherwise we would end up with a Stream<Stream<Product>>
  4. Maps each Product to its price
  5. Reduces all the prices by adding them to each other
  6. In case of the Order List being empty, returns zero.

That’s it! Now, we can create a test to assert that everything works as expected.

@Test
void getTotalPrice() {
    List<Order> orders = createOrders();
    OrderMapReducer orderMapReducer = new OrderMapReducer();
    assertEquals(new BigDecimal(17800), orderMapReducer.getTotal(orders));
}

private static List<Order> createOrders() {
    var strato = new Product("Fender", "Stratocaster", new BigDecimal(3500));
    var sg = new Product("Gibson", "SG", new BigDecimal(4800));
    var lesPaul = new Product("Gibson", "Les Paul", new BigDecimal(4500));
    var rr = new Product("Jackson", "RR", new BigDecimal(5000));

    return List.of(
            new Order("David Gilmour", List.of(strato)),
            new Order("Toni Iommi", List.of(sg)),
            new Order("Randy Rhoads", List.of(lesPaul, rr))
    );
}

As you could see, map and reduce fit to those cases when you have to extract information from a Collection.

If you have any questions, feel free to leave a message in the comment session.