In this article, we will learn how to use Predicate functional interface in Java 8. Let’s get started.
Table of contents
- Introduction to utility functional interfaces
- Predicate functional interface
- Chaining expression with Predicate
- Source code
- Benefits and Drawbacks
- Wrapping up
Introduction to utility functional interfaces
In Java 8, all utility functional interfaces are included in java.util.function package. It is useful for us to work with functional programming. Belows are functional interfaces that we will use in the next articles.
Model | Has argument | Returns a value | Description |
---|---|---|---|
Predicate | yes | boolean | Test argument and return true of false |
Function | yes | yes | Maps one type to another |
Consumer | yes | no | Consumes input (returns nothing) |
Supplier | no | yes | Generate output (using no input) |
Predicate functional interface
-
Predicate interface
Predicate is a functional interface whose functional method called test(), evaluates a condition on an input variable for a generic type.
@FunctionalInterface public interface Predicate<T> { // return true if the condition is true // and otherwise, return false boolean test(T t); }
For example:
Predicate<Integer> hasSatisfyAge = age -> age > 20; System.out.println("Will the student's age satisfy condition: " + hasSatisfyAge.test(10)); void checkAge(Predicate<Integer> p, Integer age) { boolean result = p.test(age); // do something with it }
-
BiPredicate interface
Then, we will learn the syntax of BiPredicate interface that accepts two type parameters.
@FunctionalInterface public interface Bipredicate<T, U> { boolean test(T t, U u); }
For example:
BiPredicate<Integer, String> condition = (age, name) -> age > 20 && name.startWith("John Wick"); condition.test(60, "Bill Gate");
Chaining expression with Predicate
Because the default method of Prediate that returns a new Predicate object, so we can utilize this property to create complex logical expressions.
-
Default methods
Belows are some default method of Predicate that we need to know:
// OR operation default Predicate<T> or(Predicate<? super T> other); // AND operation default Predicate<T> and(Predicate<? super T> other); // ! operation // negate() method changes the result of an existing predicate default Predicate<T> negate();
For example:
// x > 7 || x < 3 Predicate<Integer> p = x -> x > 7; p.or(x -> x < 3).test(10); // x > 7 && x % 2 == 1 p.and(x -> x % 2 == 1).test(3); // use with ! operation to reverse the result of the current predicate p.negate().test(5);
-
Static methods
Then, we continue going with static methods:
// isEquals() method uses the equals() method of the Predicate object's type parameter // to check if the argument to the test() method is equal to a value. static <T> Predicate<T> isEqual(Object targetRef); // not() method reverses the result of the calculation performed by its predicate argument. // since Java 11 static <T> Predicate<T> not(Predicate<T> target);
For example:
Predicate<Integer> p = Predicate.isEqual(5); p.test(10); p.and(Predicate.not(x -> x % 2 == 1)).test(8);
-
Overriding default methods
If we want to validate our inputs before processing it with different default methods, we need to cusomize default methods by overriding.
For example, check our string variable that starts with “a” and its length is greater than 4.
Predicate<String> isStartWithA = str -> str.charAt(0) == 'a'; Predicate<String> isLengthStatify = new Predicate<String>() { @Override public boolean test(String x) { return x.length() > 4; } @Override public Predicate<String> and(Predicate<? super String> p) { return x -> x == null ? false : test(x) && p.test(x); } };
Source code
In order to see how Predicate functional interface works, we can reference to Predicate functional interface.
When to use
-
It is used in the filtering operations of Stream API.
-
When we want to extract method technique for some complex conditions. Because we can use chaining expression to describe these complex conditions.
Benefits and Drawbacks
-
Benefits
-
It makes us writing conditions readable.
-
In a large project, it’s easy to maintain because it abides by Single Responsibility Principle.
-
It’s easy to test our business logic.
-
-
Drawbacks
Wrapping up
- Based on our business logic, we can create Predicate helper class to squeeze multiple predicate into one place.
Refer:
Functional Interfaces in Java book
https://howtodoinjava.com/java8/how-to-use-predicate-in-java-8/