Introduction
Partitioning a list is a common task in programming, especially when you need to divide a collection into two groups based on a certain condition. For example, you might want to separate a list of employees into those who earn above a certain salary and those who don’t. Java 8 introduced the Stream API, which provides a simple and effective way to partition lists into two parts using the Collectors.partitioningBy method. In this guide, we’ll explore how to partition a list using Java 8 Streams, covering various use cases with both primitive types and custom objects.
Table of Contents
- Problem Statement
- Solution Steps
- Java Program
- Partitioning a List of Integers
- Partitioning a List of Strings
- Partitioning a List of Custom Objects
- Advanced Considerations
- Conclusion
Problem Statement
The task is to create a Java program that:
- Accepts a list of elements.
- Partitions the list into two groups based on a specific condition.
- Outputs the two groups.
Example 1:
- Input: List of integers
[1, 2, 3, 4, 5, 6], partition by even and odd numbers. - Output: Two lists—one with even numbers and one with odd numbers.
Example 2:
- Input: List of custom
Studentobjects, partition by students older than 25. - Output: Two lists—one with students older than 25 and one with students 25 or younger.
Solution Steps
- Input List: Start with a list of elements that can either be hardcoded or provided by the user.
- Partition the List Using Streams: Use the
Collectors.partitioningBymethod to divide the list into two parts based on a condition. - Display the Result: Print the two groups.
Java Program
Partitioning a List of Integers
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Java 8 - Partition a List of Integers Using Streams
* Author: https://www.rameshfadatare.com/
*/
public class PartitionListIntegers {
public static void main(String[] args) {
// Step 1: Take input list
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// Step 2: Partition the list into even and odd numbers
Map<Boolean, List<Integer>> partitioned = numbers.stream()
.collect(Collectors.partitioningBy(num -> num % 2 == 0));
// Step 3: Display the result
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]
Explanation
- The
stream()method is used to create a stream from the list of integers. - The
Collectors.partitioningBymethod partitions the stream into two groups based on whether the number is even (num % 2 == 0). - The result is a
Map<Boolean, List<Integer>>, where thetruekey contains the even numbers and thefalsekey contains the odd numbers. - The output shows the two partitions: one with even numbers and one with odd numbers.
Partitioning a List of Strings
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Java 8 - Partition a List of Strings Using Streams
* Author: https://www.rameshfadatare.com/
*/
public class PartitionListStrings {
public static void main(String[] args) {
// Step 1: Take input list
List<String> fruits = Arrays.asList("apple", "banana", "orange", "avocado");
// Step 2: Partition the list into strings that start with 'a' and those that don't
Map<Boolean, List<String>> partitioned = fruits.stream()
.collect(Collectors.partitioningBy(fruit -> fruit.startsWith("a")));
// Step 3: Display the result
System.out.println("Fruits that start with 'a': " + partitioned.get(true));
System.out.println("Fruits that don't start with 'a': " + partitioned.get(false));
}
}
Output
Fruits that start with 'a': [apple, avocado]
Fruits that don't start with 'a': [banana, orange]
Explanation
- The
stream()method is used to create a stream from the list of strings. - The
Collectors.partitioningBymethod partitions the stream into two groups based on whether the string starts with the letter ‘a’. - The result is a
Map<Boolean, List<String>>, where thetruekey contains the strings that start with ‘a’ and thefalsekey contains the others. - The output shows the two partitions: one with fruits that start with ‘a’ and one with fruits that don’t.
Partitioning a List of Custom Objects
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Java 8 - Partition a List of Custom Objects Using Streams
* Author: https://www.rameshfadatare.com/
*/
public class PartitionListCustomObjects {
public static void main(String[] args) {
// Step 1: Take input list of custom objects
List<Student> students = Arrays.asList(
new Student("Raj", 25),
new Student("Anita", 30),
new Student("Vikram", 22)
);
// Step 2: Partition the list into students older than 25 and those 25 or younger
Map<Boolean, List<Student>> partitioned = students.stream()
.collect(Collectors.partitioningBy(student -> student.getAge() > 25));
// Step 3: Display the result
System.out.println("Students older than 25:");
partitioned.get(true).forEach(student ->
System.out.println(student.getName() + ": " + student.getAge())
);
System.out.println("Students 25 or younger:");
partitioned.get(false).forEach(student ->
System.out.println(student.getName() + ": " + student.getAge())
);
}
}
// Custom class Student
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
Output
Students older than 25:
Anita: 30
Students 25 or younger:
Raj: 25
Vikram: 22
Explanation
- The list of
Studentobjects is processed to partition students into those older than 25 and those who are 25 or younger. - The
Collectors.partitioningBymethod is used with a condition that checks the age of the students. - The result is a
Map<Boolean, List<Student>>, where thetruekey contains students older than 25 and thefalsekey contains the others. - The output shows the two partitions: one with students older than 25 and one with students who are 25 or younger.
Advanced Considerations
-
Handling Empty Lists: If the list is empty, the
Collectors.partitioningBymethod will return an empty map with both thetrueandfalsekeys pointing to empty lists. -
Custom Partitioning Criteria: You can customize the partitioning criteria based on any condition, making it flexible for various use cases. For example, you can partition by the length of strings, the presence of a specific character, or complex conditions on custom objects.
-
Performance Considerations: Partitioning using Streams is efficient for typical list sizes. However, for very large lists, consider testing the performance with your specific dataset, especially if the partitioning criteria are complex.
Conclusion
This guide provides methods for partitioning a list using Java 8 Streams, covering both simple lists like integers and strings, as well as more complex lists like custom objects. Java 8 Streams offer a powerful and concise way to perform this operation, making your code more readable and maintainable. Depending on your specific use case, you can easily apply the techniques demonstrated in this guide to partition a list into two distinct groups.