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.

Ops Development Stories
Ops Development Stories
Ops Development Stories
Master Java Stream API: Grouping, Sorting, Deduplication & More

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

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaDeduplicationStream APIsortinggrouping
Ops Development Stories
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.