Definition
- partitioningBy(predicate) produces
Mapwith exactly two keys:> trueandfalse. Both keys always exist, even if one list is empty. - groupingBy(classifier) produces
Mapwith 0 to N keys. Keys only appear if at least one element matches.> - partitioningBy with downstream:
partitioningBy(pred, counting())givesMapwith 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?
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());
}
}
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 |
// 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?
// 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.
// 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.
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
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.
---