Filtering and Sorting Data with Streams

Introduction

In this tutorial, we will explore how to filter and sort data using Java 8’s Streams API. These two operations are some of the most common tasks you’ll perform while working with collections of data. The Streams API provides powerful methods for performing these operations declaratively, making your code cleaner and more readable.

We will focus on:

  • Using filter() to filter data based on certain conditions.
  • Using sorted() to sort data in ascending or descending order.
  • Combining filter() and sorted() to create more complex data transformations.

Using filter() to Remove Unwanted Data

The filter() method allows you to remove unwanted elements from a stream based on a condition. It takes a Predicate as an argument, which is a functional interface that returns a boolean.

Let’s look at a simple example that filters a list of students, keeping only those who have a grade higher than 70.

Example:

import java.util.*;
import java.util.stream.*;

public class FilterExample {
    public static void main(String[] args) {
        List<Integer> grades = Arrays.asList(85, 92, 65, 70, 55, 90, 88);

        grades.stream()
              .filter(grade -> grade > 70)  // Keep grades greater than 70
              .forEach(System.out::println);  // Output: 85, 92, 90, 88
    }
}

In this example:

  • The filter() method filters out the grades less than or equal to 70.
  • forEach() is used to print the filtered grades.

Using sorted() to Sort Data

The sorted() method allows you to sort the elements of a stream. By default, it sorts elements in ascending order. You can also provide a custom comparator for custom sorting.

Example 1: Sorting Numbers in Ascending Order

import java.util.*;
import java.util.stream.*;

public class SortExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(15, 32, 8, 99, 45, 72);

        numbers.stream()
               .sorted()  // Sort in ascending order
               .forEach(System.out::println);  // Output: 8, 15, 32, 45, 72, 99
    }
}

Example 2: Sorting Numbers in Descending Order

You can reverse the order by using Comparator.reverseOrder().

import java.util.*;
import java.util.stream.*;

public class SortExampleDescending {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(15, 32, 8, 99, 45, 72);

        numbers.stream()
               .sorted(Comparator.reverseOrder())  // Sort in descending order
               .forEach(System.out::println);  // Output: 99, 72, 45, 32, 15, 8
    }
}

In this example, we use Comparator.reverseOrder() to sort the elements in descending order.


Combining filter() and sorted()

You can combine both filter() and sorted() to filter data and then sort it. This is useful when you want to apply multiple transformations to your data in one stream pipeline.

Example: Filtering and Sorting a List of Students

Let’s say you have a list of students with their names and grades. You want to filter out the students with grades less than 70 and then sort the remaining students by their grades in ascending order.

import java.util.*;
import java.util.stream.*;

public class FilterAndSortExample {
    static class Student {
        String name;
        int grade;

        Student(String name, int grade) {
            this.name = name;
            this.grade = grade;
        }

        public String getName() {
            return name;
        }

        public int getGrade() {
            return grade;
        }
    }

    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("Alice", 85),
            new Student("Bob", 92),
            new Student("Charlie", 65),
            new Student("David", 70),
            new Student("Eve", 95)
        );

        students.stream()
                .filter(student -> student.getGrade() > 70)  // Filter grades > 70
                .sorted(Comparator.comparing(Student::getGrade))  // Sort by grade
                .forEach(student -> System.out.println(student.getName() + ": " + student.getGrade()));
        // Output: Alice: 85, Bob: 92, Eve: 95
    }
}

In this example:

  • We filter students with grades greater than 70 using the filter() method.
  • Then we sort the students by grade in ascending order using the sorted() method.

Custom Sorting with Comparator

If you need to sort data based on multiple criteria or use custom sorting logic, you can provide your own comparator.

Example: Sorting Students by Name and Grade

Here’s how you can sort students first by name in ascending order, and if two students have the same name, sort them by grade in descending order:

import java.util.*;
import java.util.stream.*;

public class CustomSortExample {
    static class Student {
        String name;
        int grade;

        Student(String name, int grade) {
            this.name = name;
            this.grade = grade;
        }

        public String getName() {
            return name;
        }

        public int getGrade() {
            return grade;
        }
    }

    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("Alice", 85),
            new Student("Bob", 92),
            new Student("Charlie", 65),
            new Student("David", 70),
            new Student("Alice", 95)
        );

        students.stream()
                .sorted(Comparator.comparing(Student::getName)
                                  .thenComparing(Comparator.comparingInt(Student::getGrade).reversed()))
                .forEach(student -> System.out.println(student.getName() + ": " + student.getGrade()));
        // Output: Alice: 95, Alice: 85, Bob: 92, Charlie: 65, David: 70
    }
}

In this example:

  • Comparator.comparing() is used to sort by name.
  • thenComparing() is used to apply a secondary sorting condition for students with the same name, in this case, sorting by grade in descending order.

Summary

In this tutorial, we have covered the following:

  • Filtering data with the filter() method to remove unwanted elements.
  • Sorting data with the sorted() method in ascending or descending order.
  • Combining filter() and sorted() to apply multiple transformations in a single stream pipeline.
  • Sorting data using a custom comparator for more complex sorting logic.

The Streams API provides a declarative way to filter and sort data, allowing you to write more concise and readable code. In the next tutorial, we will explore how to handle Optional values to prevent NullPointerExceptions.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

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