Java Streams: distinct, limit, reduce and groupingBy
Remove repeats, stop early, fold a list into one value, and sort items into groups, with the output of every example.
On this page ⌄
Part 1 covered the steps you use to reshape a list. This part adds four more tools: one that removes repeats, one that stops early, one that folds many items into one, and one that sorts items into groups.
distinct: remove repeats
distinct() keeps the first copy of each item and drops the later ones:
List<Integer> nums = List.of(3, 1, 3, 2, 1);
nums.stream().distinct().toList();
// [3, 1, 2]Three is new, so it stays. One is new. The second three and the second one are already seen, so they go. The order of first appearance is kept.
limit: stop after a few items
limit(n) keeps the first n items and then stops asking for more. That makes it safe to use on a stream that never ends:
Stream.iterate(1, n -> n + 1).limit(3).toList();
// [1, 2, 3]Without limit, that stream would count up forever.
reduce: many items in, one value out
reduce takes a starting value and a rule for combining two items. It applies the rule one item at a time:
Stream.of(3, 5, 2, 4).reduce(0, Integer::sum);
// 14Start at 0, add 3 to get 3, add 5 to get 8, add 2 to get 10, add 4 to get 14.
Leave out the starting value and the result comes back in an Optional, because an empty stream has nothing to combine:
Stream.of(3, 5, 2, 4).reduce(Integer::sum); // Optional[14]
Stream.<Integer>empty().reduce(Integer::sum); // Optional.emptygroupingBy: sort items into buckets
groupingBy takes a function that picks a key for each item, and gives you a map from each key to the items that share it. Here the key is the length of the word:
List<String> words = List.of("kiwi", "fig", "apple", "pear", "mango");
Map<Integer, List<String>> byLength = words.stream()
.collect(Collectors.groupingBy(String::length));
// {3=[fig], 4=[kiwi, pear], 5=[apple, mango]}Want only the size of each group?
Pass a second collector. counting() turns each group into a number:
words.stream().collect(Collectors.groupingBy(String::length, Collectors.counting()));
// {3=1, 4=2, 5=2}mapping changes the items inside each group before they are collected:
words.stream().collect(Collectors.groupingBy(
String::length,
Collectors.mapping(String::toUpperCase, Collectors.toList())));
// {3=[FIG], 4=[KIWI, PEAR], 5=[APPLE, MANGO]}All output above was produced by running the code on Java 21.
Get the next one in your inbox
New posts, videos and free PDFs. One email a week at most.