Java Stream Filter Multiple Conditions

Introduction

In this blog post, we will explore how to use Java Stream's filter() method with multiple conditions. The Java Stream API is a powerful feature for processing and manipulating collections of objects in a concise and functional way. One of the most commonly used operations in Java Stream is the filter() method, which allows us to selectively include or exclude elements from a stream based on a specified condition.

While filtering based on a single condition is straightforward, there are situations where we need to apply multiple conditions to filter the data effectively. To filter a stream with multiple conditions, we can use lambda expressions or method references to define complex filtering predicates. These predicates can combine multiple conditions using logical operators such as && (AND) or || (OR).

Table of Contents

  1. Filter with Multiple && (AND) Conditions
  2. Filter with Multiple || (OR) Conditions
  3. Combining &&, ||, and ! Conditions
  4. Filter with Multiple Conditions on Custom Objects
  5. Example 1: Filtering Products Based on Price and Category
  6. Example 2: Filtering Employees Based on Department and Salary Range

1. Filter with Multiple && (AND) Conditions

You can filter a stream by applying multiple conditions using the && operator, which requires that all conditions must be true for an element to pass the filter.

Code Example

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FilterWithAnd {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Filter numbers greater than 3 and less than 8
        List<Integer> filteredNumbers = numbers.stream()
                                               .filter(n -> n > 3 && n < 8)
                                               .collect(Collectors.toList());

        System.out.println(filteredNumbers);
    }
}

Output

[4, 5, 6, 7]

2. Filter with Multiple || (OR) Conditions

The || operator allows you to filter elements based on multiple conditions where at least one condition must be true for an element to pass the filter.

Code Example

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FilterWithOr {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Filter numbers less than 3 or greater than 8
        List<Integer> filteredNumbers = numbers.stream()
                                               .filter(n -> n < 3 || n > 8)
                                               .collect(Collectors.toList());

        System.out.println(filteredNumbers);
    }
}

Output

[1, 2, 9, 10]

3. Combining &&, ||, and ! Conditions

You can combine multiple logical operators (&&, ||, and !) to create more complex filtering logic.

Code Example

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FilterWithComplexConditions {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Filter numbers greater than 3 and less than 8, or numbers equal to 10
        List<Integer> filteredNumbers = numbers.stream()
                                               .filter(n -> (n > 3 && n < 8) || n == 10)
                                               .collect(Collectors.toList());

        System.out.println(filteredNumbers);
    }
}

Output

[4, 5, 6, 7, 10]

4. Filter with Multiple Conditions on Custom Objects

You can apply multiple conditions to filter custom objects based on their attributes.

Code Example

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FilterCustomObjects {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("Amit", 25),
            new Person("Rahul", 35),
            new Person("Deepa", 30),
            new Person("Suresh", 40)
        );

        // Filter people whose name starts with "A" and are younger than 30
        List<Person> filteredPeople = people.stream()
                                            .filter(p -> p.getName().startsWith("A") && p.getAge() < 30)
                                            .collect(Collectors.toList());

        filteredPeople.forEach(System.out::println);
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return name + " (" + age + ")";
    }
}

Output

Amit (25)

5. Real-Time Example 1: Filtering Products Based on Price and Category

In this example, we filter the stream of Product objects by checking if the category is "Electronics" and the price is greater than $500.

Code Example

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Product {
    private String name;
    private double price;
    private String category;

    public Product(String name, double price, String category) {
        this.name = name;
        this.price = price;
        this.category = category;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    public String getCategory() {
        return category;
    }

    public static void main(String[] args) {
        List<Product> products = Arrays.asList(
                new Product("Laptop", 1200.0, "Electronics"),
                new Product("Smartphone", 800.0, "Electronics"),
                new Product("Shirt", 30.0, "Fashion"),
                new Product("TV", 900.0, "Electronics")
        );

        // Filter products with category "Electronics" and price > 500
        List<Product> filteredProducts = products.stream()
                .filter(product -> product.getCategory().equals("Electronics") && product.getPrice() > 500.0)
                .collect(Collectors.toList());

        filteredProducts.forEach(product -> System.out.println(product.getName()));
    }
}

Output

Laptop
Smartphone
TV

6. Real-Time Example 2: Filtering Employees Based on Department and Salary Range

In this example, we filter the stream of Employee objects based on multiple conditions: department being "Sales" and salary falling between $3000 and $5000.

Code Example

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Employee {
    private String name;
    private String department;
    private double salary;

    public Employee(String name, String department, double salary) {
        this.name = name;
        this.department = department;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public String getDepartment() {
        return department;
    }

    public double getSalary() {
        return salary;
    }

    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(
                new Employee("John", "Sales", 4000.0),
                new Employee("Alice", "Marketing", 4500.0),
                new Employee("Bob", "Sales", 5500.0),
                new Employee("Jane", "HR", 3000.0)
        );

        // Filter employees in "Sales" department with salary between 3000 and 5000
        List<Employee> filteredEmployees = employees.stream()
                .filter(emp -> emp.getDepartment().equals("Sales") && emp.getSalary() >= 3000.0 && emp.getSalary() <= 5000.0)
                .collect(Collectors.toList());

        filteredEmployees.forEach(emp -> System.out.println(emp.getName()));
    }
}

Output

John

Conclusion

The filter() method in Java Streams is used for applying multiple conditions to filter elements in a stream. By using logical operators such as &&, ||, and !, we can define complex predicates for filtering data based on specific criteria. Whether you're filtering simple collections or custom objects, Java Streams make this process both concise and expressive.

Comments