Performance of "filter()" method in Stream API in java

Viewed 437

I wanted to know if the stream API of java handle both condition the same way or different? If its going to execute an independent loop for each filter, then in terms of performance there is a significate difference I think. How do you think it is?

Here are the two conditions

 1. filter(cond1 && cond2 && cond3)
 2. filter(cond1).filter(cond2).filter(cond3)

Example

List<Employee> emps1 = employees.stream()                                                     
        .filter((Employee e) -> e.name.endsWith("n") && e.salary > 10000 && e.id % 2 == 1)    
        .collect(Collectors.toList());                                                        
                                                                                              
List<Employee> emps2 = employees.stream()                                                     
        .filter(e -> e.name.endsWith("n"))                                                    
        .filter(e -> e.salary > 10000)                                                        
        .filter(e -> e.id % 2 == 1)                                                           
        .collect(Collectors.toList());                                                        
1 Answers

In the case of filter(cond1 && cond2 && cond3), the processing of condition stops as soon as any of the conditions evaluates to false e.g. if cond1 evaluates to false, the other conditions (cond2 and cond3) won't be processed. Similarly, if cond1 evaluates to true, the processing will proceed to the evaluation of cond2 and if this evaluates to false, the condition, cond3 will not be evaluated.

The processing of filter(cond1).filter(cond2).filter(cond3) too happens in the same manner, as can be seen from the following example:

import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        Stream.of("one", "two", "three", "four")
        .filter(s -> {
            System.out.println("Hello");
            return s.contains("t");
        })
        .filter(s -> {
            System.out.println("Hi");
            return s.contains("f");
        })
        .forEach(System.out::println);
    }
}

Output:

Hello
Hello
Hi
Hello
Hi
Hello

Thus, it does not make any difference and it's a matter of choice. The second one looks cleaner.


Note: For more complex expressions, you can use Predicate#and which gives you two more benefits:

  1. You can reuse the behaviour implemented by the Predicate with other streams in your code.
  2. Further clean code.

Demo:

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

public class Main {
    public static void main(String[] args) {
        Predicate<String> containsT = s -> s.contains("t");
        Predicate<String> containsE = s -> s.contains("e");
        
        Stream.of("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten")
                .filter(containsT.and(containsE))
                .forEach(System.out::println);
    }
}

Output:

three
eight
ten

However, it doesn't make any difference in the way the processing happens.

Related