Summary - Advanced stream
- Java course
- Advanced
- Lesson 6/82
- 5 min
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
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 countSample solution
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
import java.util.List;
// Flatten the order lists
// Open with flatMap, sum with reduce
// Print the totalSample solution
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 |