Table of Contents
1. Introduction
Java 8 predicate is functional interface introduced in java 8. This feature is a part of the java.util.function
package, which is dedicated to functional interfaces. The primary goal of using predicates is to filter or match objects based on specific criteria.
For example, if we have a box of apples and we want to pick out only the red ones, we could use a Predicate
to check each apple and see if it’s red. If the answer is “yes,” we keep the apple; if it’s “no,” we put it back. This makes it easier to work with lists of things in our programs, allowing us to sort, filter, and choose items based on whatever rules we set up.
2. Understanding the Predicate
A Predicate
is a single-argument functional interface that returns a boolean value, either true or false. It accepts one argument and yields a result as either true or false.
1 2 3 4 5 6 7 8 9 10 11 12 |
// Using anonymous class Predicate<Integer> predicate=new Predicate<Integer>() { @Override public boolean test(Integer i) { return i > 100; } }; // Using lambda expression Predicate<Integer> predicate = i -> i > 100; |
Here is the definition of Predicate
interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
package java.util.function; import java.util.Objects; /** * Represents a predicate (boolean-valued function) of one argument. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #test(Object)}. * * @param <T> the type of the input to the predicate * * @since 1.8 */ @FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } default Predicate<T> negate() { return (t) -> !test(t); } default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } } |
3. Predicate Methods Example
There are multiple methods in Predicate interface. Let’s go through them one by one.
3.1 test()
This is abstract method of Predicate interface. It evaluates true if predicate matches the input argument.
Here is simple example of test()
method which checks if input argument is greater than 100 or not.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package org.arpit.java2blog; import java.util.function.Predicate; public class Java8PredicateExample { public static void main(String[] args) { Predicate<Integer> predicate = i -> i > 100; boolean greaterCheck = predicate.test(200); System.out.println("is 200 greater than 100: "+greaterCheck); } } |
Output:
You can pass Predicate as a function argument too.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package org.arpit.java2blog; import java.util.function.Predicate; public class Java8PredicateMethodExample { public static void main(String[] args) { boolean greaterCheckBoolean = greaterCheck(200, p -> p > 100); System.out.println(greaterCheckBoolean); } public static boolean greaterCheck(int number, Predicate<Integer> predicate) { return predicate.test(number); } } |
3.2 and()
The and()
is a default method that returns a composite predicate, denoting the logical AND of this predicate and the one passed as an argument.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package org.arpit.java2blog; import java.util.function.Predicate; public class Java8PredicateAndExample { public static void main(String[] args) { Predicate<Integer> predicate1 = i -> i > 100; Predicate<Integer> predicate2 = i -> i < 300; Predicate<Integer> andPredicate = predicate1.and(predicate2); boolean rangeCheck = andPredicate.test(200); System.out.println("200 lies between 100 and 300: "+ rangeCheck); } } |
Output:
We have created two predicates and checked the logical AND between predicate1
and predicate2
.
3.3 or()
The or()
is a default method that returns a composite predicate, indicating the logical OR of this predicate and the one passed as an argument.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package org.arpit.java2blog; import java.util.function.Predicate; public class Java8PredicateAndExample { public static void main(String[] args) { Predicate<Integer> predicate1 = i -> i > 100; Predicate<Integer> predicate2 = i -> i < 50; Predicate<Integer> andPredicate = predicate1.or(predicate2); boolean rangeCheck = andPredicate.test(30); System.out.println("(30 > 100) or (30 < 50) returns: "+ rangeCheck); } } |
Output:
We have created two predicates and checked logical or between predicate1
and predicate2
3.4 negate()
The negate()
method is a default method that returns a predicate, representing the logical negation of this predicate.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package org.arpit.java2blog; import java.util.function.Predicate; public class Java8PredicateAndExample { public static void main(String[] args) { Predicate<Integer> predicate = i -> i > 100; Predicate<Integer> negatePredicate = predicate.negate(); // Negate predicate will become i -> i < 100 boolean rangeCheck = negatePredicate.test(30); System.out.println("30 is less than 100: "+ rangeCheck); } } |
Output:
We have used negate()
method to change predicate
(integer greater than 100) to negatePredicate
(integer lesser than 100).
3.5 isEqual()
The isEqual()
is astatic method that returns a predicate, determining if two arguments are equal based on the object’s equals() method. This method is particularly useful when we need to evaluate objects in a functional style, for instance, when filtering a collection.
Imagine we have a list of strings and we want to find which ones are equal to a given string, say “Java”. We can use the isEqual() method to create a predicate for this comparison and then apply it to our list.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
List<String> languages = Arrays.asList("Java", "Python", "C++", "Java", "JavaScript"); // Create a Predicate using isEqual() to check for equality with "Java" Predicate<String> isEqualToJava = Predicate.isEqual("Java"); // Filter the list based on the Predicate List<String> filteredLanguages = languages.stream() .filter(isEqualToJava) .collect(Collectors.toList()); System.out.println(filteredLanguages); |
4. Filtering List Using Predicate
In Java 8, the stream’s filter
method accepts a Predicate
as an argument, enabling us to filter lists using predicates. This mechanism allows for the application of specific conditions to streamline the process of selecting elements from collections based on our defined criteria, enhancing both the functionality and readability of our code.
Lets say you have student class as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
package org.arpit.java2blog; public class Student { private int id; private String name; private String gender; private int age; public Student(int id, String name, String gender, int age) { super(); this.id = id; this.name = name; this.gender = gender; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + "]"; } } |
Lets create a function which will be used to filter students based on predicates:
1 2 3 4 5 |
public static List filterStudents (List students,Predicate predicate) { return students.stream().filter(predicate).collect(Collectors.toList()); } |
Lets create a main class as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
package org.arpit.java2blog; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; public class Java8PredicateStudentExample { public static void main(String[] args) { List<Student> studentList = createStudentList(); // Filter all male student who have age > 18 Predicate<Student> predicate1 = s -> s.getGender().equalsIgnoreCase("M") && s.getAge() > 18; List<Student> students1 = filterStudents(studentList, predicate1); System.out.println("Male students having age > 18 are :" + students1); // Filer all female student who have age < 18 Predicate<Student> predicate2 = s -> s.getGender().equalsIgnoreCase("F") && s.getAge() < 18; List<Student> students2 = filterStudents(studentList, predicate2); System.out.println("Female students having age < 18 are :" + students2); } public static List<Student> filterStudents(List<Student> students, Predicate<Student> predicate) { return students.stream().filter(predicate).collect(Collectors.toList()); } public static List<Student> createStudentList() { List<Student> studentList = new ArrayList<>(); Student s1 = new Student(1, "Arpit", "M", 19); Student s2 = new Student(2, "John", "M", 17); Student s3 = new Student(3, "Mary", "F", 14); Student s4 = new Student(4, "Martin", "M", 21); Student s5 = new Student(5, "Monica", "F", 16); Student s6 = new Student(6, "Ally", "F", 20); studentList.add(s1); studentList.add(s2); studentList.add(s3); studentList.add(s4); studentList.add(s5); studentList.add(s6); return studentList; } } |
When you run above program, you will get below output: