Java 8 – Partition a List Using Streams

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 Student objects, partition by students older than 25.
  • Output: Two lists—one with students older than 25 and one with students 25 or younger.

Solution Steps

  1. Input List: Start with a list of elements that can either be hardcoded or provided by the user.
  2. Partition the List Using Streams: Use the Collectors.partitioningBy method to divide the list into two parts based on a condition.
  3. 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.partitioningBy method 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 the true key contains the even numbers and the false key 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.partitioningBy method 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 the true key contains the strings that start with ‘a’ and the false key 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 Student objects is processed to partition students into those older than 25 and those who are 25 or younger.
  • The Collectors.partitioningBy method is used with a condition that checks the age of the students.
  • The result is a Map<Boolean, List<Student>>, where the true key contains students older than 25 and the false key 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.partitioningBy method will return an empty map with both the true and false keys 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.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top