โ† Back to list

๐Ÿ”ฅ Java 8 Stream APIโ€Šโ€”โ€ŠA Complete Guide (Part-2)

Advanced Java 8 Stream APIโ€Šโ€”โ€ŠgroupingBy, partitioningBy, flatMap, Custom Collectors & More

Prince Singh in Javarevisited ยท 2025-10-18 09:42 ยท 5 claps ยท 3.6 min read
#java8 #java8-streams #grouping-and-sorting #flatmap #collector
Open on Medium โ†—

๐Ÿ”ฅ Java 8 Stream API โ€” A Complete Guide (Part-2)

Advanced Java 8 Stream API โ€” groupingBy, partitioningBy, flatMap, Custom Collectors & More

Stream API Advanced

Stream API Advanced

๐Ÿ“ Part-1: Java 8 Stream API โ€” A Complete Guide

In Part-1, we explored the fundamentals of Java 8 Stream API like map, filter, and reduce.

In this part, weโ€™ll dive deeper into powerful operations that help solve real-world problems, including:

  • Grouping and partitioning collections
  • Flattening nested data
  • Creating custom collectors
  • Multi-level aggregations

Collectors.groupingBy()

  • A classifier function that maps an element to a key.
  • (Optional) Downstream collector (e.g., counting, summing, mapping, etc.)
  • It returns a Map<K, List<T>> (or another Map<K, R> if using downstream collectors).
Collectors.groupingBy(Function<? super T, ? extends K>)
Collectors.groupingBy(Function, Collector)

โœ… Problem Statement:

You need to group employees by their department to populate a department-wise team view.

public class Employee {
    String name;
    String department;

Employee(String name, String department) {
        this.name = name;
        this.department = department;
    }
    public String getDepartment() { return department; }
    public String getName() { return name; }
}

List<Employee> employees = Arrays.asList(
    new Employee("Alice", "HR"),
    new Employee("Bob", "Engineering"),
    new Employee("Charlie", "HR"),
    new Employee("David", "Engineering")
);

Map<String, List<Employee>> groupedByDept = employees.stream()
    .collect(Collectors.groupingBy(Employee::getDepartment));
groupedByDept.forEach((dept, empList) -> {
    String names = empList.stream()
                          .map(Employee::getName)
                          .collect(Collectors.joining(", "));
    System.out.println(dept + ": " + names);
});

โœ… Output:

HR: Alice, Charlie  
Engineering: Bob, David

Collectors.partitioningBy()

  • A Predicate to test each element (returns true/false).
  • A Map<Boolean, List<T>> where:
  • true โ†’ elements matching the predicate
  • false โ†’ the rest
Collectors.partitioningBy(Predicate<? super T>)

โœ… Problem Statement:

You need to separate even and odd numbers from a list of integers.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

Map<Boolean, List<Integer>> partitioned = numbers.stream()
    .collect(Collectors.partitioningBy(n -> n % 2 == 0));

System.out.println("Even numbers: " + partitioned.get(true));
System.out.println("Odd numbers: " + partitioned.get(false));

โœ… Output:

Even numbers: [2, 4, 6]  
Odd numbers: [1, 3, 5]

flatMap() โ€” Flattening Nested Structures

  • A function that returns a Stream for each element.
  • A flattened stream of all sub-elements.
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)

โœ… Problem Statement:

You have a nested list of programming languages, and you want a flat list of all languages.

List<List<String>> nestedList = Arrays.asList(
    Arrays.asList("Java", "Python"),
    Arrays.asList("C++", "Go"),
    Arrays.asList("Rust")
);

List<String> flatList = nestedList.stream()
    .flatMap(List::stream)
    .collect(Collectors.toList());
System.out.println(flatList);

โœ… Output:

[Java, Python, C++, Go, Rust]

Custom Collectors

Collector.of(Supplier, Accumulator, Combiner, Finisher)

What it takes:

  • Supplier โ†’ provides new container
  • Accumulator โ†’ adds elements to container
  • Combiner โ†’ merges containers (parallel streams)
  • Finisher โ†’ final transformation
  • A custom aggregation result โ€” e.g., formatted string, calculated value, etc.

โœ… Problem Statement:

You want to join a list of strings in uppercase, separated by " | ".

List<String> words = Arrays.asList("java", "stream", "collector");

Collector<String, StringJoiner, String> customCollector = Collector.of(
    () -> new StringJoiner(" | "),
    (joiner, word) -> joiner.add(word.toUpperCase()),
    StringJoiner::merge,
    StringJoiner::toString
);
String result = words.stream().collect(customCollector);
System.out.println(result);

โœ… Output:

JAVA | STREAM | COLLECTOR

Real-World Example: Group & Count

Method: groupingBy + counting

Count how many elements are grouped under each key.

Collectors.groupingBy(..., Collectors.counting())

Returns:

A Map<K, Long>

โœ… Problem Statement:

You want to count how many books each author has written.

class Book {
    String title;
    String author;

Book(String title, String author) {
        this.title = title;
        this.author = author;
    }
    public String getAuthor() { return author; }
}
List<Book> books = Arrays.asList(
    new Book("Book A", "Author 1"),
    new Book("Book B", "Author 2"),
    new Book("Book C", "Author 1"),
    new Book("Book D", "Author 3"),
    new Book("Book E", "Author 2")
);
Map<String, Long> bookCountByAuthor = books.stream()
    .collect(Collectors.groupingBy(Book::getAuthor, Collectors.counting()));
bookCountByAuthor.forEach((author, count) -> 
    System.out.println(author + ": " + count));

โœ… Output:

Author 1: 2  
Author 2: 2  
Author 3: 1

Nested Grouping

Collectors.groupingBy(Classifier1, groupingBy(Classifier2))

What it does:

Groups elements in multiple levels, like by department โ†’ then by designation โ†’ then by list of employees.

โœ… Problem Statement

You need to generate multi-level reports, like employees grouped by department and then by designation.

class Employee {
    String name;
    String department;
    String designation;

Employee(String name, String department, String designation) {
        this.name = name;
        this.department = department;
        this.designation = designation;
    }
    public String getDepartment() { return department; }
    public String getDesignation() { return designation; }
    public String getName() { return name; }
}
List<Employee> employees = Arrays.asList(
    new Employee("Alice", "HR", "Manager"),
    new Employee("Bob", "Engineering", "Developer"),
    new Employee("Charlie", "HR", "Recruiter"),
    new Employee("David", "Engineering", "Developer"),
    new Employee("Eva", "Engineering", "Manager")
);
Map<String, Map<String, List<Employee>>> multiLevelGroup = employees.stream()
    .collect(Collectors.groupingBy(Employee::getDepartment,
             Collectors.groupingBy(Employee::getDesignation)));
multiLevelGroup.forEach((dept, desMap) -> {
    System.out.println("Department: " + dept);
    desMap.forEach((designation, empList) -> {
        String names = empList.stream()
                              .map(Employee::getName)
                              .collect(Collectors.joining(", "));
        System.out.println("  " + designation + ": " + names);
    });
});

โœ… Output:

Department: HR  
Manager: Alice  
Recruiter: Charlie  
Department: Engineering  
Developer: Bob, David  
Manager: Eva

โš ๏ธ Tips for Using Advanced Stream API

  • โœ… flatMap() is powerful for flattening but can make code harder to read โ€” use wisely.
  • โœ… groupingBy() and partitioningBy() are great for aggregation โ€” but watch out for memory usage in large datasets.
  • โœ… Use Collectors.toMap() when you want to directly create a Map<K, V>.
  • โœ… Prefer custom collectors when built-in ones donโ€™t solve the problem exactly.

โœ… Conclusion

Java 8โ€™s Stream API is a true game-changer โ€” with its advanced operations, you can handle complex grouping, data flattening, partitioning, and custom aggregations, all in a clean, declarative, and readable way. Whether youโ€™re processing logs, generating reports, or working with nested data, mastering these techniques will help you write modern, efficient, and maintainable Java code.

Happy coding! ๐Ÿ’ปโœจ


๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
post_id
3b8f6d43fcc8
slug
java-8-stream-api-a-complete-guide-part-2-3b8f6d43fcc8
url
https://medium.com/javarevisited/java-8-stream-api-a-complete-guide-part-2-3b8f6d43fcc8
canonical_url
https://medium.com/javarevisited/java-8-stream-api-a-complete-guide-part-2-3b8f6d43fcc8
author_url
https://medium.com/@singhprince0088
status
ok
fetched_at
2026-07-17 00:53:25