Partition Even and Odd Numbers
Java coding interview problem for Java 8 Streams: Partition Even and Odd Numbers.
Partitioning a collection into two groups is a common Java Stream API interview problem.
A very common example:
Separate Even Numbers
and
Odd Numbers
This problem introduces:
- Stream API
- Predicate
Collectors.partitioningBy()- Functional programming
- Data grouping techniques
What is Partitioning?
Partitioning means dividing a collection into two groups based on a condition.
The condition returns:
true
or
false
Example:
Numbers:
[1,2,3,4,5,6]
Condition:
number % 2 == 0
Result:
true → Even Numbers
false → Odd Numbers
Understanding Even and Odd Numbers
A number is:
Even
If divisible by 2.
Example:
2
4
6
8
Condition:
number % 2 == 0
Odd
If not divisible by 2.
Example:
1
3
5
7
Condition:
number % 2 != 0
Why This Problem is Important?
This problem tests:
1. Stream API Knowledge
Understanding:
stream()
filter()
collect()
2. Functional Programming
Using:
Lambda expressions
Predicates
3. Collector Understanding
Especially:
Collectors.partitioningBy()
4. Data Processing Patterns
The same approach applies to:
- Employee classification
- Transaction filtering
- Order processing
- Validation rules
Array Partitioning Concept
Traditional approach:
Input Array
↓
Loop Through Elements
↓
Check Condition
↓
Store Result
Stream approach:
Collection
↓
Stream
↓
Predicate
↓
Partition
↓
Result Map
Real-World Applications
Employee Management
Partition employees:
Salary > $100,000
Salary <= $100,000
Banking Systems
Partition transactions:
Successful
Failed
E-Commerce
Partition orders:
Delivered
Pending
Security Systems
Partition users:
Active
Inactive
Problem Statement
Given a list of integers, partition numbers into:
Even Numbers
and
Odd Numbers
using Java Streams.
Input Example
[1,2,3,4,5,6,7,8]
Expected Output
Even:
[2,4,6,8]
Odd:
[1,3,5,7]
Partitioning Visualization
Input:
1 2 3 4 5 6
Condition:
number % 2 == 0
Processing:
1 → false
2 → true
3 → false
4 → true
5 → false
6 → true
Result:
true:
[2,4,6]
false:
[1,3,5]
Approach 1 — Traditional Loop Approach
Before Streams, developers commonly used loops.
Algorithm
- Create two lists.
- Traverse numbers.
- Check even/odd condition.
- Add to corresponding list.
Java Program
import java.util.*;
public class PartitionEvenOdd {
public static Map<String,List<Integer>>
partition(List<Integer> numbers) {
List<Integer> even =
new ArrayList<>();
List<Integer> odd =
new ArrayList<>();
for(Integer number : numbers) {
if(number % 2 == 0) {
even.add(number);
} else {
odd.add(number);
}
}
Map<String,List<Integer>> result =
new HashMap<>();
result.put(
"Even",
even
);
result.put(
"Odd",
odd
);
return result;
}
}
Dry Run
Input:
[1,2,3,4,5]
Initial:
Even = []
Odd = []
Read:
1
Odd:
[1]
Read:
2
Even:
[2]
Read:
3
Odd:
[1,3]
Read:
4
Even:
[2,4]
Read:
5
Odd:
[1,3,5]
Final:
Even:
[2,4]
Odd:
[1,3,5]
Complexity Analysis — Loop Approach
Let:
n = number of elements
Traversal:
O(n)
Adding elements:
O(1)
Total Time:
O(n)
Space:
O(n)
because two lists are created.
Approach 2 — Using Stream filter()
A simple Stream solution uses two filters.
Even Numbers
List<Integer> evenNumbers =
numbers.stream()
.filter(
number ->
number % 2 == 0
)
.toList();
Odd Numbers
List<Integer> oddNumbers =
numbers.stream()
.filter(
number ->
number % 2 != 0
)
.toList();
Complete Example
import java.util.*;
public class EvenOddUsingStreams {
public static void main(String[] args) {
List<Integer> numbers =
Arrays.asList(
1,2,3,4,5,6
);
List<Integer> even =
numbers.stream()
.filter(
n -> n % 2 == 0
)
.toList();
List<Integer> odd =
numbers.stream()
.filter(
n -> n % 2 != 0
)
.toList();
System.out.println(even);
System.out.println(odd);
}
}
Output
[2,4,6]
[1,3,5]
Problem With Two filter() Calls
The above solution works.
But it processes the stream twice.
Flow:
First traversal:
Find Even
Second traversal:
Find Odd
For large collections:
More processing
Better solution:
partitioningBy()
Approach 3 — Using Collectors.partitioningBy()
Java provides a collector specifically for two-way partitioning.
Syntax:
Collectors.partitioningBy(
Predicate
)
Example:
Collectors.partitioningBy(
number -> number % 2 == 0
)
Meaning:
true → Even
false → Odd
Java Program — partitioningBy()
import java.util.*;
import java.util.stream.Collectors;
public class PartitionUsingStreams {
public static Map<Boolean,List<Integer>>
partition(List<Integer> numbers) {
return numbers.stream()
.collect(
Collectors.partitioningBy(
number ->
number % 2 == 0
)
);
}
}
Output
Input:
[1,2,3,4,5,6]
Output:
{
true=[2,4,6],
false=[1,3,5]
}
Step-by-Step Explanation
Input:
[1,2,3,4,5,6]
Condition:
number % 2 == 0
Process:
1 → false
2 → true
3 → false
4 → true
5 → false
6 → true
Collector creates:
true:
[2,4,6]
false:
[1,3,5]
Stream Pipeline
List<Integer>
↓
stream()
↓
partitioningBy()
↓
Predicate Evaluation
↓
Map<Boolean,List<Integer>>
Complexity Analysis
Traversal:
O(n)
Partition insertion:
O(1)
Total:
O(n)
Space:
O(n)
Advantages
- Single traversal.
- Clean and readable.
- Designed specifically for two groups.
- Works well with Stream API.
Drawbacks
- Returns Boolean keys.
- Requires understanding Collector API.
- Not suitable for more than two groups.
Deep Dive into Collectors.partitioningBy()
Collectors.partitioningBy() is a special Stream collector used when data needs to be divided into exactly two groups.
The two groups are based on:
Predicate Result
which returns:
true
or
false
partitioningBy() Syntax
Basic syntax:
Collectors.partitioningBy(
Predicate
)
Example:
numbers.stream()
.collect(
Collectors.partitioningBy(
n -> n % 2 == 0
)
);
Result:
true → Even Numbers
false → Odd Numbers
Internal Working
When Stream processes elements:
Element
↓
Predicate Check
↓
true / false
↓
Store In Bucket
Example:
Input:
[1,2,3,4]
Predicate:
n -> n % 2 == 0
Processing:
1 → false
2 → true
3 → false
4 → true
Buckets:
true:
[2,4]
false:
[1,3]
Difference Between partitioningBy() and groupingBy()
Both methods group data, but their purpose is different.
partitioningBy()
Used when there are:
Only two groups
Example:
Even
Odd
Returns:
Map<Boolean,List<T>>
Example:
{
true=[2,4,6],
false=[1,3,5]
}
groupingBy()
Used when there can be:
Multiple groups
Example:
Employee departments:
IT
HR
Finance
Returns:
Map<Key,List<Value>>
Comparison Table
| Feature | partitioningBy() | groupingBy() |
|---|---|---|
| Groups | Two | Multiple |
| Condition | Predicate | Classifier Function |
| Key Type | Boolean | Any Type |
| Example | Even/Odd | Department |
| Use Case | Binary split | Category grouping |
Custom Partition Conditions
Partitioning is not limited to even and odd numbers.
Any boolean condition can be used.
Example — Partition Positive and Negative Numbers
Input:
[-5,-2,0,3,8]
Condition:
n -> n >= 0
Java:
Map<Boolean,List<Integer>> result =
numbers.stream()
.collect(
Collectors.partitioningBy(
n -> n >= 0
)
);
Output:
true:
[0,3,8]
false:
[-5,-2]
Partition Numbers Into Prime and Non-Prime
Example:
Input:
[2,3,4,5,6,7]
Condition:
isPrime(number)
Prime Check Method
public static boolean isPrime(int number) {
if(number <= 1) {
return false;
}
for(int i = 2;
i <= Math.sqrt(number);
i++) {
if(number % i == 0) {
return false;
}
}
return true;
}
Partition Using Predicate
Map<Boolean,List<Integer>> result =
numbers.stream()
.collect(
Collectors.partitioningBy(
NumberPartition::isPrime
)
);
Output:
true:
[2,3,5,7]
false:
[4,6]
Partition Employees by Salary
Real-world example:
Separate:
High Salary Employees
Low Salary Employees
Employee:
John 90000
Alice 150000
Bob 70000
Condition:
salary >= 100000
Java Program
Map<Boolean,List<Employee>> result =
employees.stream()
.collect(
Collectors.partitioningBy(
employee ->
employee.getSalary() >= 100000
)
);
Output:
true:
Alice
false:
John
Bob
Partition Objects Using Streams
Streams can partition any object type.
Examples:
Orders
Completed
Pending
Users
Active
Inactive
Transactions
Success
Failure
Example:
Collectors.partitioningBy(
Transaction::isSuccessful
)
Multiple Partition Levels
Sometimes applications need nested partitioning.
Example:
Employees:
Salary
+
Department
First partition:
High Salary
Low Salary
Then group:
Department
Example:
employees.stream()
.collect(
Collectors.partitioningBy(
Employee::isHighSalary,
Collectors.groupingBy(
Employee::getDepartment
)
)
);
Result:
true:
IT → employees
HR → employees
false:
IT → employees
Finance → employees
Custom Predicate Examples
A Predicate represents:
Input
↓
true / false
Example 1 — Age Classification
Predicate<Person> adult =
person ->
person.getAge() >= 18;
Partition:
Adults
Minors
Example 2 — Product Availability
product ->
product.getStock() > 0
Result:
Available
Out Of Stock
Stream vs Loop Comparison
| Feature | Loop | Stream |
|---|---|---|
| Code | More | Less |
| Readability | Simple | Declarative |
| Performance | Slightly faster | Comparable |
| Parallel Processing | Manual | Supported |
| Functional Style | No | Yes |
Parallel Stream Considerations
For large collections:
parallelStream()
can process data using multiple threads.
Example:
numbers.parallelStream()
.collect(
Collectors.partitioningBy(
n -> n % 2 == 0
)
);
However:
Consider:
- Data size
- Thread overhead
- Order requirements
For small lists:
Normal stream()
is usually better.
HashMap Internal Working
partitioningBy() internally creates a map structure.
Conceptually:
Map<Boolean,List<T>>
|
+------ true bucket
|
+------ false bucket
Example:
true
|
[2,4,6]
false
|
[1,3,5]
Common Interview Mistakes
Mistake 1
Using groupingBy for binary conditions.
Example:
Even/Odd
Better:
partitioningBy()
Mistake 2
Expecting more than two groups.
Wrong:
partitioningBy(department)
Use:
groupingBy()
Mistake 3
Forgetting Boolean keys.
Result:
Map<Boolean,List<T>>
not:
List<List<T>>
Mistake 4
Using parallel streams unnecessarily.
For small data:
parallelStream()
may reduce performance.
Edge Cases
| Case | Handling |
|---|---|
| Empty list | Returns empty true/false lists |
| All even | False list empty |
| All odd | True list empty |
| Null values | Filter before partition |
| Large data | Consider parallel streams |
Interview Follow-up Questions
Q1. Difference between partitioningBy() and groupingBy()?
Q2. How does partitioningBy work internally?
Q3. Partition employees by salary range.
Q4. Can partitioningBy create more than two groups?
Q5. How to combine partitioningBy with groupingBy?
Q6. How to partition custom objects?
Q7. What is the return type of partitioningBy()?
Related Java Collection Problems
- Group Employees by Department
- Find Duplicate Elements Using Streams
- Character Frequency Using Streams
- Find Highest Salary Employee
- Convert List to Map
- Custom Comparator Examples
Key Takeaways
Partitioning pattern:
Collection
↓
Predicate
↓
true / false
↓
Two Groups
Use:
Two groups
Collectors.partitioningBy()
Use:
Multiple groups
Collectors.groupingBy()
Examples:
Even/Odd:
n -> n % 2 == 0
Salary:
employee ->
employee.getSalary() >= 100000
Order:
transaction ->
transaction.isCompleted()
Complexity:
Time:
O(n)
Space:
O(n)
Frequently Asked Interview Questions
Q1. What does partitioningBy return?
A:
Map<Boolean,List<T>>
Q2. Why use partitioningBy instead of groupingBy?
A:
Because the result has exactly two groups based on a condition.
Q3. Can partitioningBy work with objects?
A:
Yes. Any object can be partitioned using a Predicate.
Q4. Is partitioningBy faster than groupingBy?
A:
For binary classification, partitioningBy is more expressive and optimized for the use case.
Interview Tip
When asked:
"Partition data using Java Streams."
Explain:
- Identify the true/false condition.
- Use
Collectors.partitioningBy(). - For more than two categories use
groupingBy(). - Combine collectors for complex reporting.
- Discuss performance and parallel processing.
For senior Java interviews, discuss:
- Predicate design.
- Collector internals.
- Nested collectors.
- Stream performance.
- Enterprise data classification patterns.
This demonstrates strong understanding of Java Streams, Collectors, and functional programming techniques.