Back to Collectors
Q2Question 2 of 21

Collectors.partitioningBy: boolean two-bucket split vs groupingBy

Key Concepts
  • partitioningBy(predicate) returns Map<Boolean, List<T>> with exactly TWO keys: true and false
  • Both keys always exist, even if one group is empty (guaranteed by the API)
  • groupingBy returns Map<K, List<T>> with 0 to N keys, only for groups that have elements
  • partitioningBy accepts a downstream collector for counting, mapping, or summing within each partition
  • partitioningBy is a specialized case of groupingBy for boolean classification
  • Prefer partitioningBy over groupingBy(Boolean::valueOf) for binary splits because it is more efficient and guarantees both keys

Definition

partitioningBy splits elements into exactly two groups (true/false) with both keys guaranteed, while groupingBy creates N groups with only keys that have matching elements.
  • partitioningBy(predicate) produces Map> with exactly two keys: true and false. Both keys always exist, even if one list is empty.
  • groupingBy(classifier) produces Map> with 0 to N keys. Keys only appear if at least one element matches.
  • partitioningBy with downstream: partitioningBy(pred, counting()) gives Map with counts per partition.
  • partitioningBy is more efficient than groupingBy(e -> predicate.test(e) ? true : false) because it is optimized for the two-bucket case.
  • Use partitioningBy for inherently binary splits: active/inactive, pass/fail, above/below threshold.

At National Bank of India, the compliance team splits all accounts into two piles: above minimum balance and below. partitioningBy always gives both piles, even if every account is above minimum (the "below" pile is empty but still reported). groupingBy would only give the piles that have accounts.

Understanding the Concepts

How does partitioningBy work?

JAVA
package com.bank.analytics;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

public class PartitionDemo {
    record Account(String id, String holder, BigDecimal balance) {}

    public static void main(String[] args) {
        List<Account> accounts = List.of(
            new Account("SAV2001", "Rajesh", new BigDecimal("50000")),
            new Account("SAV2002", "Priya",  new BigDecimal("5000")),
            new Account("SAV2003", "Amit",   new BigDecimal("150000")),
            new Account("SAV2004", "Kavita", new BigDecimal("8000"))
        );

        BigDecimal minBalance = new BigDecimal("10000");

        Map<Boolean, List<Account>> partitioned = accounts.stream()
            .collect(Collectors.partitioningBy(
                a -> a.balance().compareTo(minBalance) >= 0));

        System.out.println("Compliant: " + partitioned.get(true).size());
        System.out.println("Below minimum: " + partitioned.get(false).size());
    }
}
TEXT
Compliant: 2
Below minimum: 2

How is this different from groupingBy?

| Feature | partitioningBy | groupingBy |
|---------|---------------|------------|
| Keys | Exactly 2 (true, false) | 0 to N |
| Both keys guaranteed | Yes | No |
| Classifier type | Predicate (boolean) | Function (any type) |
| Use case | Binary split | Multi-category |

JAVA
// groupingBy: keys only exist for groups that have elements
Map<String, List<Account>> byHolder = accounts.stream()
    .collect(Collectors.groupingBy(Account::holder));
// Only keys: Rajesh, Priya, Amit, Kavita

How do you use a downstream collector?

JAVA
// Count per partition
Map<Boolean, Long> counts = accounts.stream()
    .collect(Collectors.partitioningBy(
        a -> a.balance().compareTo(minBalance) >= 0,
        Collectors.counting()));
// {true=2, false=2}

// Sum balance per partition
Map<Boolean, Double> sums = accounts.stream()
    .collect(Collectors.partitioningBy(
        a -> a.balance().compareTo(minBalance) >= 0,
        Collectors.summingDouble(a -> a.balance().doubleValue())));

What are common mistakes?

WRONG: Assuming groupingBy with a boolean classifier is the same as partitioningBy.

JAVA
// groupingBy with Boolean: may MISS the false key if all elements are true
Map<Boolean, List<Account>> wrong = accounts.stream()
    .collect(Collectors.groupingBy(
        a -> a.balance().compareTo(minBalance) >= 0));
// If all accounts are compliant: {true=[...]} -- false key MISSING!

CORRECT: partitioningBy guarantees both keys.

JAVA
Map<Boolean, List<Account>> correct = accounts.stream()
    .collect(Collectors.partitioningBy(
        a -> a.balance().compareTo(minBalance) >= 0));
// Always: {true=[...], false=[]} -- false key present even if empty

What should a senior engineer know?

  • The guaranteed presence of both keys matters for downstream code that does result.get(false).size() without null checks.
  • partitioningBy creates a Partition (internal Map implementation) that always has exactly two entries, making it slightly more memory-efficient than a HashMap.
  • For more than two categories, use groupingBy. For boolean splits, always use partitioningBy.

Visual Overview

DIAGRAM
  accounts: [SAV2001(50K), SAV2002(5K), SAV2003(150K), SAV2004(8K)]
       │
       ▼
  partitioningBy(balance >= 10K)
       │
  ┌────┴────────────────────────────────┐
  │  true:  [SAV2001(50K), SAV2003(150K)] │
  │  false: [SAV2002(5K), SAV2004(8K)]    │
  └──────────────────────────────────────┘
  Both keys always present.

Key Takeaway

partitioningBy is a specialized groupingBy for boolean predicates. It always returns a Map with exactly two keys (true and false), both guaranteed to exist even if one group is empty. groupingBy returns a Map with 0 to N keys, where keys only appear if at least one element matches.

Use partitioningBy for binary splits: settled/unsettled, pass/fail, active/inactive. Use groupingBy for multi-value classification. Both accept downstream collectors for counting, mapping, or summing within each group.

At National Bank of India, the compliance report partitions accounts into compliant and below-minimum-balance. The guaranteed presence of both keys means the report always has both sections, even if all accounts are compliant.

Remember one sentence: partitioningBy always gives exactly two buckets with both keys guaranteed, while groupingBy gives only keys that have matching elements.

---

Share
Use ← → arrow keys to navigate