What is the difference between a Predicate and a Function Interface in Java8?
There's really no difference.
In theory, there shouldn't be any functional difference between Predicate<T>
and Function<T, Boolean>
. A Predicate
is just a function that takes an object of some type and returns a boolean. A Function
is a generalization which can return any type, not just Boolean
's.
There may be implementation details within Java itself that make them distinct, but they should be the same in theory.
An example would be if an interface could only accept a Predicate<String>
, not a Function<String, Boolean
.
Difference between Predicate<T>
and Function<T, R>
First and foremost a Predicate<T>
is strictly a boolean-valued function:
_ _ _ _ _ _ _
| |
T --> | predicate | --> boolean
|_ _ _ _ _ _ _|
Whereas this is not necessarily true for a Function<T, R>
:
_ _ _ _ _ _ _
| |
T --> | function | --> R
|_ _ _ _ _ _ _|
The latter consumes any type of object just as Predicate<T>
enables but can vary in the return type.
Use case of Predicate<T>
and Function<T, R>
The use case for Predicate<T>
is when you require a function that consumes one argument of type T
and returns a boolean. e.g. that may be in a situation where you want to filter a stream of elements, find the first element from a stream that satisfies a condition as such of .filter(predicate).findFirst()
, or checking the presence of an element from a stream that satisfies a certain condition as such of anyMatch
, noneMatch
, allMatch
etc.
The use case for Function<T, R>
is when you require a function that consumes one argument of type T
and transforms that into a type R
e.g. that may be when calling stream.map(func)
.
Explanation of your code snippet:
In regards to the example snippet in your post Predicate<String>
and Function<String, Boolean>
are the same thing in terms of what they represent i.e. they both represent a function taking a String
and returning a boolean
. However, the former avoids boxing the returned value from boolean
to Boolean
whereas the latter does not.
That said, this does not necessarily mean wherever you can use a Predicate<String>
you can also use a Function<String, Boolean>
or vice versa.
Example:
While this compiles:
Predicate<String> predicate = p -> p.length() == 21;
Stream<String> stream = stringList().stream().filter(predicate);
This does not:
Function<String, Boolean> function = p -> p.length() == 21;
Stream<String> stream = stringList().stream().filter(function);
and vice versa:
While this works:
Function<String, Boolean> function = p -> p.length() == 21;
Stream<Boolean> stream = stringList().stream().map(function);
This does not:
Predicate<String> predicate = p -> p.length() == 21;
Stream<Boolean> stream = stringList().stream().map(predicate);
in this case there is no difference, it matters only to the things you can apply to. So for example allMatch
expects a Predicate
, you can't pass a Function
, even if logically they do the same thing.
Aominè's answer covers the basic differences. I would like to add that the two interfaces also have different specialized default methods, i.e. methods you can call on any implementing class:
Predicate<T>
Predicate<T> and(Predicate<? super T> other)
- Returns a composed predicate that represents a short-circuiting logical AND of this predicate and another.Predicate<T> or(Predicate<? super T> other)
- Returns a composed predicate that represents a short-circuiting logical OR of this predicate and another.negate()
- Returns a predicate that represents the logical negation of this predicate.
Function<T,R>
<V> Function<T,V> andThen(Function<? super R,? extends V> after)
- Returns a composed function that first applies this function to its input, and then applies theafter
function to the result.<V> Function<V,R> compose(Function<? super V,? extends T> before)
- Returns a composed function that first applies thebefore
function to its input, and then applies this function to the result.
As you can see, Predicate
has useful methods for creating complex conditions, much like the operators you would use in a regular if
statement, whereas Function
has methods that support simple chaining.