Step 1 of 7 · Reading · ~3 min
Learn
Generics, Streams, and Functional Java
Streams API
In Java Intermediate you wrote source, filter, map and terminal pipelines, and counted with groupingBy(..., counting()). This lesson is about collectors: describing the whole result of a pipeline, grouped and summarised, as one value, and about the traps in ordering, laziness and parallelism. You will be able to turn a list of records into a sorted report without a single mutable variable.
Downstream collectors
groupingBy takes the classifier and, as a second argument, a downstream collector applied to each group. Three-argument form lets you pick the map type:
Map<String, Integer> cents = orders.stream().collect(
Collectors.groupingBy(o -> o.city, TreeMap::new, Collectors.summingInt(o -> o.cents)));
TreeMap::new matters: the default is a HashMap, whose iteration order is unspecified, so printing it gives output that depends on hash codes. Useful downstream collectors:
| Collector | Result per group |
|---|---|
counting() | Long |
summingInt(f) / averagingInt(f) | Integer / Double |
summarizingInt(f) | IntSummaryStatistics: count, sum (a long), min, max, average |
mapping(f, downstream) | apply f, then collect with downstream |
maxBy(cmp) / minBy(cmp) | Optional<T> |
joining(", ") | String (on a stream of strings) |
summingInt returns an int and wraps silently past 2,147,483,647. summarizingInt keeps a long sum.
Two results from one pass: teeing
Collectors.teeing (Java 12) feeds every element to two collectors and merges their results, so you traverse the data once:
String span = orders.stream().collect(Collectors.teeing(
Collectors.minBy(Comparator.comparingInt((Order o) -> o.cents)),
Collectors.maxBy(Comparator.comparingInt((Order o) -> o.cents)),
(lo, hi) -> lo.get().cents + ".." + hi.get().cents));
maxBy and minBy return an Optional because the stream may be empty. Ties go to whichever comparator order you give: maxBy picks the element the comparator ranks greatest, and when two compare equal it keeps the first one seen. To break ties yourself, chain thenComparing; Comparator.reverseOrder() on the second key makes the alphabetically smaller name rank higher.
Flattening and merging
flatMap replaces each element by a stream and concatenates them. toMap throws IllegalStateException on a duplicate key unless you pass a merge function:
Map<String, Integer> letters = Stream.of("to", "be", "or", "not")
.flatMap(w -> w.chars().mapToObj(c -> String.valueOf((char) c)))
.collect(Collectors.toMap(ch -> ch, ch -> 1, Integer::sum, TreeMap::new));
Laziness and infinite sources
Intermediate operations do nothing until a terminal operation pulls elements through, one at a time, and short-circuiting operations stop early. That is what makes infinite streams usable:
Stream.iterate(1, x -> x * 3).takeWhile(x -> x < 500).forEach(System.out::println); // 1 3 9 27 81 243
takeWhile stops at the first failure; filter would keep testing forever. A stream can be consumed once; reusing it throws IllegalStateException.
Parallel streams
parallel() splits the work over the common ForkJoinPool. It is correct only when the lambdas are stateless, do not touch shared variables, and reductions are associative. forEach on a parallel stream has no order; forEachOrdered does, at a cost. Appending to a shared ArrayList from a parallel forEach loses elements. Measure before using it: small inputs run slower.
Common mistakes
- Printing a
HashMapfromgroupingBy. The order differs from the sorted order the task asks for; passTreeMap::new. summingInton large values. The total wraps to a negative number.- Dividing two ints for an average.
total / counttruncates before it reaches the formatter. - Resolving a tie by accident.
maxBywith a comparator that ignores the tie-break key returns the first seen, which depends on input order.
Your exercise
Build a per-department report from a list of employees in a single collect call. The parsing and printing are in the starter. The likely mistake is the tie rule for the top earner.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…