I'm assuming you're talking about com.google.common.base.Predicate<T>
from Guava.
From the API:
Determines a true
or false
value for a given input. For example, a RegexPredicate
might implement Predicate<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
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