Master Java Stream API: Grouping, Sorting, Deduplication & More
This guide demonstrates essential Java Stream API techniques—including grouping collections into maps, extracting first entries, performing reductions to find max or min, converting streams to lists, sorting, removing duplicates, and a comprehensive list of frequently used stream operations—providing practical code examples for Java 11 and 17.
Java 17 and Java 11 now have similar JDK adoption rates as Java 8. Below are several frequently used Stream API operations, covering grouping, conversion, sorting, deduplication, and other common methods.
Grouping
Collecting a List into a Map<Key, List<StreamItem>>:
List<StreamItem> streamList = Stream.of(
new StreamItem(1, "k1"),
new StreamItem(2, "k1"),
new StreamItem(3, "k2"),
new StreamItem(4, "k2")).collect(Collectors.toList());
System.out.println(streamList);
// 1.1 Grouping
Map<String, List<StreamItem>> streamMap1 = streamList.stream()
.collect(Collectors.groupingBy(StreamItem::getKey));
System.out.println(streamMap1);
// Output:
// {k1=[StreamItem{id=1, key='k1', name='i_1|k_k1'}, StreamItem{id=2, key='k1', name='i_2|k_k1'}],
// k2=[StreamItem{id=3, key='k2', name='i_3|k_k2'}, StreamItem{id=4, key='k2', name='i_4|k_k2'}]}Collecting to a Map<Key, Object> that keeps only the first entry:
// 1.2 Keep first entry
Map<String, StreamItem> streamMap2 = Stream.of(
new StreamItem(1, "k1"),
new StreamItem(2, "k2"))
.collect(Collectors.toMap(StreamItem::getKey, Function.identity()));
// Duplicate keys will throw java.lang.IllegalStateException: Duplicate key
System.out.println(streamMap2);
// Output:
// {k1=StreamItem{id=1, key='k1', name='i_1|k_k1'},
// k2=StreamItem{id=2, key='k2', name='i_2|k_k2'}}Grouping with sorting inside each group to obtain max or min values:
Comparator<StreamItem> idComparator = Comparator.comparing(StreamItem::getId);
Map<String, Optional<StreamItem>> streamMap3 = streamList.stream()
.collect(Collectors.groupingBy(StreamItem::getKey,
Collectors.reducing(BinaryOperator.maxBy(idComparator))));
System.out.println(streamMap3);
// Output:
// {k1=Optional[StreamItem{id=2, key='k1', name='i_2|k_k1'}],
// k2=Optional[StreamItem{id=4, key='k2', name='i_4|k_k2'}]}List Conversion
Partition a list and flatten it back to a single list:
List<List<StreamItem>> partitionList = Lists.partition(streamList, 2);
List<StreamItem> streamList1 = partitionList.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(streamList1);
// Output:
// [StreamItem{id=1, key='k1', name='i_1|k_k1'},
// StreamItem{id=2, key='k1', name='i_2|k_k1'},
// StreamItem{id=3, key='k2', name='i_3|k_k2'},
// StreamItem{id=4, key='k2', name='i_4|k_k2'}]Sorting
Default ascending order; use reversed() for descending:
// 3.1 Ascending
List<StreamItem> streamList2 = Stream.of(
new StreamItem(3, "k1"),
new StreamItem(1, "k1"),
new StreamItem(2, "k2"))
.sorted(Comparator.comparing(StreamItem::getId))
.collect(Collectors.toList());
System.out.println(streamList2);
// For descending: Comparator.comparing(StreamItem::getId).reversed()Deduplication
Remove duplicates while keeping the last written value (by sorting descending and using a TreeSet):
// 4.1 Deduplicate
List<StreamItem> streamList3 = Stream.of(
new StreamItem(3, "k1"),
new StreamItem(1, "k1"),
new StreamItem(2, "k2"))
.sorted(Comparator.comparing(StreamItem::getId).reversed())
.collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(StreamItem::getKey))),
ArrayList::new));
System.out.println(streamList3);
// Output:
// [StreamItem{id=3, key='k1', name='i_3|k_k1'},
// StreamItem{id=2, key='k2', name='i_2|k_k2'}]Other Common APIs
filter – filter elements by condition
max – obtain maximum value
min – obtain minimum value
count – count elements
sum – sum of numeric elements
average – average of numeric elements
distinct – remove duplicate elements
sorted – natural order sorting (ascending by default, can be set to descending)
limit, skip – limit or skip elements, useful for pagination
map – transform elements
collect, toList – collect into a list (no deduplication)
collect, toSet – collect into a set (deduplication)
toArray – convert stream to array
mapToInt, distinct – convert to IntStream and deduplicate
reduce – aggregate (sum, max, min, product)
findFirst – find first element
findAny – find any element
allMatch – check if all elements match a predicate
anyMatch – check if any element matches a predicate
noneMatch – check if no elements match a predicate
flatMap – flatten nested streams
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ops Development Stories
Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
