Real-World Grouping with Collectors.groupingBy() in Java

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.

▶️ Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube

If you’ve worked with Java Streams, chances are you’ve heard of Collectors.groupingBy(). It’s one of the most powerful features for aggregating and organizing data — especially when you’re dealing with large datasets in real-world applications.

In this guide, you’ll learn:

  • ✅ What groupingBy() is and how it works
  • 📊 How to use it in real-world scenarios
  • 🔄 Advanced tricks like nested grouping and downstream collectors
  • ⚖️ When to use groupingBy() vs partitioningBy()

📦 What Is Collectors.groupingBy()?

Collectors.groupingBy() is a collector used with Java Streams to group elements of a collection by a classification function, returning a Map<K, List<T>> by default.

🔤 Basic Syntax:

Map<K, List<T>> map = stream.collect(Collectors.groupingBy(classifier));

🧱 Domain Model for Examples

We’ll use the following classes for our examples:

record Product(String name, String category, double price) {}

Sample data:

List<Product> products = List.of(
    new Product("iPhone", "Electronics", 90000),
    new Product("TV", "Electronics", 40000),
    new Product("Shirt", "Clothing", 1500),
    new Product("Jeans", "Clothing", 2000),
    new Product("Laptop", "Electronics", 120000)
);

✅ 1. Group Products by Category

Map<String, List<Product>> groupedByCategory = products.stream()
    .collect(Collectors.groupingBy(Product::category));

groupedByCategory.forEach((category, items) -> {
    System.out.println(category + ": " + items);
});

🧾 Output:

Electronics: [iPhone, TV, Laptop]
Clothing: [Shirt, Jeans]

✅ 2. Group and Count Products per Category

Use a downstream collector to count grouped items:

Map<String, Long> countByCategory = products.stream()
    .collect(Collectors.groupingBy(
        Product::category,
        Collectors.counting()
    ));

System.out.println(countByCategory);

🧾 Output:

Electronics: 3
Clothing: 2

✅ 3. Group by Category and Sum Prices

Map<String, Double> totalByCategory = products.stream()
    .collect(Collectors.groupingBy(
        Product::category,
        Collectors.summingDouble(Product::price)
    ));

System.out.println(totalByCategory);

🧾 Output:

Electronics: 250000.0
Clothing: 3500.0

✅ 4. Nested Grouping: Category → Price Range

Let’s group products first by category, then by price range.

Map<String, Map<String, List<Product>>> nestedGrouping = products.stream()
    .collect(Collectors.groupingBy(
        Product::category,
        Collectors.groupingBy(p -> {
            if (p.price() > 50000) return "Expensive";
            else return "Affordable";
        })
    ));

System.out.println(nestedGrouping);

🧾 Output:

Electronics: {
    Expensive=[iPhone, Laptop],
    Affordable=[TV]
}
Clothing: {
    Affordable=[Shirt, Jeans]
}

✅ 5. Grouping with Custom Collection (Set Instead of List)

Map<String, Set<String>> productNamesByCategory = products.stream()
    .collect(Collectors.groupingBy(
        Product::category,
        Collectors.mapping(Product::name, Collectors.toSet())
    ));

System.out.println(productNamesByCategory);

🧾 Output:

Electronics: [TV, Laptop, iPhone]
Clothing: [Shirt, Jeans]

✅ 6. Top Product per Category (Max by Price)

Map<String, Optional<Product>> mostExpensiveProduct = products.stream()
    .collect(Collectors.groupingBy(
        Product::category,
        Collectors.maxBy(Comparator.comparingDouble(Product::price))
    ));

System.out.println(mostExpensiveProduct);

🧾 Output:

Electronics: Laptop
Clothing: Jeans

✅ 7. Custom Key Grouping: First Letter of Product Name

Map<Character, List<Product>> byFirstLetter = products.stream()
    .collect(Collectors.groupingBy(p -> p.name().charAt(0)));

System.out.println(byFirstLetter);

🧾 Output:

i: [iPhone]
T: [TV]
S: [Shirt]
J: [Jeans]
L: [Laptop]

⚖️ groupingBy() vs partitioningBy()

Feature groupingBy() partitioningBy()
Keys Multiple (any type) Only two groups: true and false
Use case Group by any field/classifier Split data based on a boolean test
Return type Map<K, List<T>> Map<Boolean, List<T>>

🧪 Example:

Map<Boolean, List<Product>> expensivePartition = products.stream()
    .collect(Collectors.partitioningBy(p -> p.price() > 50000));

🧠 Final Thoughts

The Collectors.groupingBy() method is one of the most versatile tools in the Java Stream API. Whether you need to:

  • Group by one or more fields
  • Count, sum, or aggregate
  • Apply nested groupings or transformations

Start with basic groupings and then move into nested and custom downstream collectors as your use cases grow.

My Top and Bestseller Udemy Courses. The sale is going on with a 70 - 80% discount. The discount coupon has been added to each course below:

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare