Stage 4: Modern Java, lesson 3 of 7

Collectors: grouping, partitioning and joining

Intermediate3 min read@since 16Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

collect(…) turns a stream into a result using a Collector. The most useful ones:

  • Collectors.toList(), toSet(), toMap(key, value)
  • groupingBy(classifier): a map of lists, such as {Pune=[…], Delhi=[…]}
  • groupingBy(classifier, downstream): group, then count, sum, average or map each group
  • partitioningBy(predicate): exactly two groups, true and false
  • joining(", "): concatenate strings
  • counting(), summingInt, averagingDouble, summarizingInt
  • teeing(c1, c2, merger) (Java 12): two results in one pass

toMap throws on duplicate keys unless you pass a merge function.

Example

Java
record Sale(String city, String product, int qty, double amount) {}
List<Sale> sales = List.of(
    new Sale("Pune", "Java book", 2, 998), new Sale("Delhi", "Java book", 1, 499),
    new Sale("Pune", "Spring course", 1, 2999), new Sale("Delhi", "Mouse", 3, 1200));

Map<String, Double> revenueByCity = sales.stream()
    .collect(Collectors.groupingBy(Sale::city, TreeMap::new, Collectors.summingDouble(Sale::amount)));
// {Delhi=1699.0, Pune=3997.0}

Map<Boolean, List<Sale>> bigAndSmall = sales.stream()
    .collect(Collectors.partitioningBy(s -> s.amount() > 1000));

String products = sales.stream().map(Sale::product).distinct().sorted()
    .collect(Collectors.joining(", ", "[", "]"));        // [Java book, Mouse, Spring course]

Map<String, Integer> qtyByProduct = sales.stream()
    .collect(Collectors.toMap(Sale::product, Sale::qty, Integer::sum));   // merges duplicates

IntSummaryStatistics stats = sales.stream().collect(Collectors.summarizingInt(Sale::qty));
System.out.println(stats.getMax() + " " + stats.getAverage());

Common mistake

Calling toMap when keys can repeat, without a merge function. It throws IllegalStateException: Duplicate key.

Under the hood

groupingBy returns a HashMap by default; pass a map supplier such as TreeMap::new for sorted keys. For parallel streams, groupingByConcurrent avoids merging per-thread maps. When a collector gets complicated, a plain loop is often clearer and just as fast.

Check yourself

Which collector concatenates strings with a separator?

How this connects

Where this leads

You've reached the end of this thread. Try a learning path for what's next.

Part of Crack the Java interview, Upgrade from Java 8 to Java 25.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.