CodeBlanks Logo Icon CodeBlanks

Summary - Advanced stream

Combine groupingBy, reduce and flatMap to write a sales summarizer.

Summary - Stream advanced

In this group you met five advanced collectors. groupingBy groups elements by a key; partitioningBy splits into two groups; joining merges strings; reduce folds into one value; flatMap flattens nested streams.

Combining them yields powerful solutions. For example, you can pass counting into groupingBy to count per group; or call reduce after flatMap to produce a single total out of nested structures. These combinations keep the code short and readable.

Practice Count products per category with groupingBy + counting

Create a list of four products (record Product(String name, String category, double price)): two Office, two Grocery. Get a Map<String, Long> with counts per category using Collectors.groupingBy(Product::category, TreeMap::new, Collectors.counting()). Then print each category and its count with forEach.

Starter code

Main.java
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

record Product(String name, String category, double price) {}

// Group products by category and count
// Use groupingBy + counting + TreeMap
// Print each category's count

Sample solution

Main.java
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

record Product(String name, String category, double price) {}

public class CategoryCounts {
    public static void main(String[] args) {
        List<Product> products = List.of(
            new Product("Pen", "Office", 12.5),
            new Product("Notebook", "Office", 25.0),
            new Product("Bread", "Grocery", 5.0),
            new Product("Milk", "Grocery", 15.0)
        );
        Map<String, Long> counts = products.stream()
            .collect(Collectors.groupingBy(Product::category, TreeMap::new, Collectors.counting()));
        counts.forEach((k, v) -> System.out.println(k + ": " + v));
    }
}

Expected output

Office: 2
Grocery: 2

Which collector when?

Choosing the right collector depends on the question. Use groupingBy to split into categories; partitioningBy to split in two by one condition; joining to merge strings; reduce to produce a single value; flatMap to flatten nested structures.

You can also chain these. Open nested data with flatMap first, then fold it into a single result with reduce. This approach solves multi-step data-processing tasks in a single stream pipeline.

Practice Sum nested orders with flatMap + reduce

Create a List<List<Double>> with three inner lists: List.of(12.5, 25.0), List.of(5.0, 8.0), List.of(30.0). Flatten the stream with flatMap(List::stream), then sum with reduce(0.0, Double::sum). Print the result with System.out.println.

Starter code

Main.java
import java.util.List;

// Flatten the order lists
// Open with flatMap, sum with reduce
// Print the total

Sample solution

Main.java
import java.util.List;

public class SumAllPrices {
    public static void main(String[] args) {
        List<List<Double>> orders = List.of(
            List.of(12.5, 25.0),
            List.of(5.0, 8.0),
            List.of(30.0)
        );
        double total = orders.stream()
            .flatMap(List::stream)
            .reduce(0.0, Double::sum);
        System.out.println(total);
    }
}

Expected output

80.5

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Which collector splits elements into two groups and returns Map<Boolean, List<T>>?

  • Collectors.groupingBy
  • Collectors.partitioningBy Correct answer
  • Collectors.joining
  • Collectors.toList

Explanation: partitioningBy produces two groups from a single condition.

2 Match each collector with its output type

Term Meaning
groupingBy Map<K, List<T>>
partitioningBy Map<Boolean, List<T>>
joining String
reduce(identity, op) T

All lessons in Advanced