What is the difference between using a Predicate or a function as a Java stream filter?

AdHominem picture AdHominem · Apr 22, 2016 · Viewed 7.2k times · Source

So assuming I use some random filter on a stream, the most straightforward way is to directly input the Predicate:

x.stream().filter(e -> e % 2 == 0)

As well I can simply make a reference and define the Predicate in advance:

Predicate<Integer> isEven = e -> e % 2 == 0;
...
x.stream().filter(isEven)

But I can as well use a function:

private static boolean isEven(Integer integer) {
    return integer % 2 == 0;
}
...
x.stream().filter(MyClass::isEven)

As far as I can tell, the Predicate is of course much more limited while the function might have side effects etc. But since people like Venkat Subramaniam use the latter solution, I really wonder: What are the main differences here?

Answer

Grzegorz Piwowarek picture Grzegorz Piwowarek · Apr 22, 2016

No! Predicate is not really limited in comparison to a method reference! In fact, these things are all the same!

Just look at the filter() function signature: filter(Predicate<? super T> predicate)

And let's consider your examples:

x.stream().filter(e -> e % 2 == 0)

Predicate<Integer> isEven = e -> e % 2 == 0;
...
x.stream().filter(isEven)

The first one is just an inlined version of the latter.

private static boolean isEven(Integer integer) {
return integer % 2 == 0;
}
...
x.stream().filter(MyClass::isEven)

and here you can see Method References in action. MR are just a syntactic sugar allowing you to define Lambda Expression based on already existing functions.

At the end of the day all those expressions become the same implementation of Predicate functional interface.

Also, you can also perform side effects in your Lambda Expressions by using block syntax on the right side but it's generally not advised:

e -> {
    //side effects here
    return e % 2 == 0;
}