Skip to main content

Collectors in Depth

intermediate15 min readLesson 79 of 180

groupingBy with downstream collectors, partitioningBy, toMap with merge functions, and teeing for two-at-once reductions.

Collectors: reshaping data in one pass

Beginner streams end at collect(toList()). The real power is reshaping:

// group orders by customer
Map<String, List<Order>> byCustomer =
    orders.stream().collect(Collectors.groupingBy(Order::customer));

// count per group — groupingBy + counting downstream
Map<String, Long> counts =
    words.stream().collect(Collectors.groupingBy(w -> w, Collectors.counting()));

// partition into two buckets by a predicate
Map<Boolean, List<Integer>> parts =
    nums.stream().collect(Collectors.partitioningBy(n -> n % 2 == 0));

// toMap with a merge function (duplicate keys otherwise explode)
Map<String, Integer> merged =
    sales.stream().collect(Collectors.toMap(
        Sale::region, Sale::amount, Integer::sum));

teeing runs two collectors at once and merges their results — perfect for "average and max" style passes over one stream.