Predicate in Java
I'm assuming you're talking about com.google.common.base.Predicate<T>
from Guava.
From the API:
Determines a
true
orfalse
value for a given input. For example, aRegexPredicate
might implementPredicate<String>
, and return true for any string that matches its given regular expression.
This is essentially an OOP abstraction for a boolean
test.
For example, you may have a helper method like this:
static boolean isEven(int num) {
return (num % 2) == 0; // simple
}
Now, given a List<Integer>
, you can process only the even numbers like this:
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
for (int number : numbers) {
if (isEven(number)) {
process(number);
}
}
With Predicate
, the if
test is abstracted out as a type. This allows it to interoperate with the rest of the API, such as Iterables
, which have many utility methods that takes Predicate
.
Thus, you can now write something like this:
Predicate<Integer> isEven = new Predicate<Integer>() {
@Override public boolean apply(Integer number) {
return (number % 2) == 0;
}
};
Iterable<Integer> evenNumbers = Iterables.filter(numbers, isEven);
for (int number : evenNumbers) {
process(number);
}
Note that now the for-each loop is much simpler without the if
test. We've reached a higher level of abtraction by defining Iterable<Integer> evenNumbers
, by filter
-ing using a Predicate
.
API links
-
Iterables.filter
- Returns the elements that satisfy a predicate.
On higher-order function
Predicate
allows Iterables.filter
to serve as what is called a higher-order function. On its own, this offers many advantages. Take the List<Integer> numbers
example above. Suppose we want to test if all numbers are positive. We can write something like this:
static boolean isAllPositive(Iterable<Integer> numbers) {
for (Integer number : numbers) {
if (number < 0) {
return false;
}
}
return true;
}
//...
if (isAllPositive(numbers)) {
System.out.println("Yep!");
}
With a Predicate
, and interoperating with the rest of the libraries, we can instead write this:
Predicate<Integer> isPositive = new Predicate<Integer>() {
@Override public boolean apply(Integer number) {
return number > 0;
}
};
//...
if (Iterables.all(numbers, isPositive)) {
System.out.println("Yep!");
}
Hopefully you can now see the value in higher abstractions for routines like "filter all elements by the given predicate", "check if all elements satisfy the given predicate", etc make for better code.
Unfortunately Java doesn't have first-class methods: you can't pass methods around to Iterables.filter
and Iterables.all
. You can, of course, pass around objects in Java. Thus, the Predicate
type is defined, and you pass objects implementing this interface instead.
See also
- Wikipedia/Higher-order function
- Wikipedia/Filter (higher-order function)
A predicate is a function that returns a true/false (i.e. boolean) value, as opposed to a proposition which is a true/false (i.e. boolean) value. In Java, one cannot have standalone functions, and so one creates a predicate by creating an interface for an object that represents a predicate and then one provides a class that implements that interface. An example of an interface for a predicate might be:
public interface Predicate<ARGTYPE>
{
public boolean evaluate(ARGTYPE arg);
}
And then you might have an implementation such as:
public class Tautology<E> implements Predicate<E>
{
public boolean evaluate(E arg){
return true;
}
}
To get a better conceptual understanding, you might want to read about first-order logic.
Edit
There is a standard Predicate interface (java.util.function.Predicate) defined in the Java API as of Java 8. Prior to Java 8, you may find it convenient to reuse the com.google.common.base.Predicate interface from Guava.
Also, note that as of Java 8, it is much simpler to write predicates by using lambdas. For example, in Java 8 and higher, one can pass p -> true
to a function instead of defining a named Tautology subclass like the above.