Menu

Java Stream Filter

Java Stream Filter

A Stream in Java is a sequence of elements or objects. Streams are introduced in Java 8. They allow us to perform various operations on a data source in an efficient manner.

In this tutorial, we will learn how to filter streams in Java.

Stream.filter() Method

The filter() method of Streams allows us to filter a given stream based on a condition or a predicate.

Note that this method will not alter the given stream. It will return a new stream that contains the elements satisfying the condition. The signature of the method is shown below.

Stream<T> filter(Predicate<? super T> condition)  

Let's take a look at a few examples to understand its working.

Example 1: Filter Stream in Java

Let's filter out all the elements greater than 7 from a Stream. We will create a Stream from a List and then apply the filter() method on this Stream.

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class Demo
{
    public static void main(String[] args)
    {
        List<Integer> list = Arrays.asList(7, 9, 1, 2, 5, 11, 21);
        System.out.println("The List is: " + list);
        
        Predicate<Integer> numGreaterThanSeven = p -> (p > 7);//Writing the condition or Predicate
        
        Stream<Integer> s = list.stream();//Stream of the list
        Stream<Integer> filteredStream = s.filter(numGreaterThanSeven);
        
        System.out.println("Filtered Elements are: ");
        filteredStream.forEach(System.out :: println);
    }
}

The List is: [7, 9, 1, 2, 5, 11, 21] Filtered Elements are: 9 11 21

Example 2: Filter Stream of User data

Let's work on a user-defined class. We will create the Student class defined below.

class Student
{
    private String name;
    private int regNo;
    private Double gpa;
    
    Student(String s, int i, Double gpa)
    {
        this.name = s;
        this.regNo = i;
        this.gpa = gpa;
    }    
    //Getters and Setters
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getRegNo() {
        return regNo;
    }
    public void setRegNo(int regNo) {
        this.regNo = regNo;
    }
    public Double getGpa() {
        return gpa;
    }
    public void setGpa(Double gpa) {
        this.gpa = gpa;
    }    
}

Let's filter out all Students whose GPA is greater than 8. We will create a Predicate for this condition and use it with the filter() method.

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class Demo
{
    public static void main(String[] args)
    {
        Student s1 = new Student("Jack", 102, 8.55);
        Student s2 = new Student("Joe", 101, 8.75);
        Student s3 = new Student("Clay", 107, 9.1);
        Student s4 = new Student("Simon", 105, 7.99);
        Student s5 = new Student("Reacher", 103, 7.00);
        
        List<Student> list = Arrays.asList(s1, s2, s3, s4, s5);
                
        Predicate<Student> gpaGreaterThanEight = c -> c.getGpa() > 8.0;//Lambda expression for Predicate
        
        Stream filteredStream = list.stream().filter(gpaGreaterThanEight);
    }
}

We can also define a method in the Student class that returns a boolean value. Then, we can use this method directly with the filter() method. We will collect the filtered stream into a List by using the collect() method.

public boolean gpaGreaterThanEight()
{
    return this.getGpa() > 8.0;
}
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;


public class Demo
{
    public static void main(String[] args)
    {
        Student s1 = new Student("Jack", 102, 8.55);
        Student s2 = new Student("Joe", 101, 8.75);
        Student s3 = new Student("Clay", 107, 9.1);
        Student s4 = new Student("Simon", 105, 7.99);
        Student s5 = new Student("Reacher", 103, 7.00);

        List<Student> list = Arrays.asList(s1, s2, s3, s4, s5);
        System.out.println("The Student List is: ");
        for(Student s : list)
            System.out.println(s.getName() + " " + s.getRegNo() + " " + s.getGpa());
    
        Stream filteredStream = list.stream().filter(Student :: gpaGreaterThanEight);//Class Method for Predicate 
        List<Student> filteredList = (List<Student>) filteredStream.collect(Collectors.toList());
        
        System.out.println("\nThe Filtered List is: ");
        for(Student s : filteredList)
            System.out.println(s.getName() + " " + s.getRegNo() + " " + s.getGpa());
    }
}

The Student List is: Jack 102 8.55 Joe 101 8.75 Clay 107 9.1 Simon 105 7.99 Reacher 103 7.0 The Filtered List is: Jack 102 8.55 Joe 101 8.75 Clay 107 9.1

Example 3: Filter Stream by using Lambda Expression

We can also use multiple conditions for filtering. These conditions can be created using Lambda expressions in the Predicate. Or we can create a method in the user-defined class(if we are using a user-defined class). Let's continue with the previous example and filter out all Students whose GPA is greater than eight and name contains exactly three characters.

Let's first use a Lambda expression to accomplish our task.

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Demo
{
    public static void main(String[] args)
    {
        Student s1 = new Student("Jack", 102, 8.55);
        Student s2 = new Student("Joe", 101, 8.75);
        Student s3 = new Student("Clay", 107, 9.1);
        Student s4 = new Student("Simon", 105, 7.99);
        Student s5 = new Student("Reacher", 103, 7.00);

        List<Student> list = Arrays.asList(s1, s2, s3, s4, s5);
        System.out.println("The Student List is: ");
        for(Student s : list)
            System.out.println(s.getName() + " " + s.getRegNo() + " " + s.getGpa());
    
        Predicate<Student> p = c -> (c.getGpa() > 8.0) && (c.getName().length() == 3);
        
        Stream filteredStream = list.stream().filter(p);
        List<Student> filteredList = (List<Student>) filteredStream.collect(Collectors.toList());
        
        System.out.println("\nThe Filtered List is: ");
        for(Student s : filteredList)
            System.out.println(s.getName() + " " + s.getRegNo() + " " + s.getGpa());
    }
}

The Student List is: Jack 102 8.55 Joe 101 8.75 Clay 107 9.1 Simon 105 7.99 Reacher 103 7.0 The Filtered List is: Joe 101 8.75

Let's define a method in the Student class that checks the two conditions and returns a boolean value accordingly.

public boolean predicateCondition()
{
    if(this.getGpa() > 8.0 && this.getName().length() == 3)
        return true;
    else
        return false;
}
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Demo
{
    public static void main(String[] args)
    {
        Student s1 = new Student("Jack", 102, 8.55);
        Student s2 = new Student("Joe", 101, 8.75);
        Student s3 = new Student("Clay", 107, 9.1);
        Student s4 = new Student("Simon", 105, 7.99);
        Student s5 = new Student("Reacher", 103, 7.00);

        List<Student> list = Arrays.asList(s1, s2, s3, s4, s5);
        System.out.println("The Student List is: ");
        for(Student s : list)
            System.out.println(s.getName() + " " + s.getRegNo() + " " + s.getGpa());
        
        Stream filteredStream = list.stream().filter(Student :: predicateCondition);
        List<Student> filteredList = (List<Student>) filteredStream.collect(Collectors.toList());
        
        System.out.println("\nThe Filtered List is: ");
        for(Student s : filteredList)
            System.out.println(s.getName() + " " + s.getRegNo() + " " + s.getGpa());
    }
}

The Student List is: Jack 102 8.55 Joe 101 8.75 Clay 107 9.1 Simon 105 7.99 Reacher 103 7.0 The Filtered List is: Joe 101 8.75

Exception Handling in Lambda Expression

A checked or unchecked exception may occur in our Lambda expression that we use for Predicates. It is a good idea to use try-catch blocks in lambda expressions to handle exceptions.

Predicate<Student> p = c ->
                   {
                       try{
                           return c.predicateCondition(); 
                       }
                       catch(Exception e) {
                           System.out.print(e);
                       }
                       return false;
                   };

We can also use third-party libraries like the ThrowingFunction library to handle checked exceptions. We will use the ThrowingPredicate class of this library. It will return a wrapped exception.

try
{
        List<Student> customersWithValidProfilePhoto = list
                      .stream()
                      .filter(ThrowingPredicate.unchecked(Student :: predicateCondition))
                      .collect(Collectors.toList());
}
catch(Exception e)
{
        System.out.print(e);
}

If an exception occurs in the above code, then we will get the following output.

pl.touk.throwing.exception.WrappedException

Summary

A Stream is just a sequence of elements. The filter() method allows us to filter out elements from a Stream based on a condition. The condition is defined using a Predicate. We can either use Lambda Expressions or class methods(for user-defined classes) to create a Predicate. The Predicate plays a crucial role in determining how the elements will be filtered.