The Predicate
interface in Java is a functional interface that represents a single argument function that returns a boolean value. It is part of the java.util.function
package and is often used for filtering or matching conditions. This interface is very useful in the context of lambda expressions, as it allows you to define inline logic for evaluating conditions.
The Predicate
interface is defined as follows:
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
// Default methods for composing predicates
default Predicate<T> and(Predicate<? super T> other) {
// implementation
}
default Predicate<T> negate() {
// implementation
}
default Predicate<T> or(Predicate<? super T> other) {
// implementation
}
static <T> Predicate<T> isEqual(Object targetRef) {
// implementation
}
}
test(T t)
: The single abstract method that evaluates the predicate on the given argument.and(Predicate<? super T> other)
: Returns a composed predicate that represents a short-circuiting logical AND of this predicate and another.negate()
: Returns a predicate that represents the logical negation of this predicate.or(Predicate<? super T> other)
: Returns a composed predicate that represents a short-circuiting logical OR of this predicate and another.isEqual(Object targetRef)
: Returns a predicate that tests if two arguments are equal according to Objects.equals(Object, Object)
.Lambda expressions provide a concise way to create instances of the Predicate
interface. Below are various examples demonstrating how to use Predicate
with lambda expressions.
Here is a simple example of using a Predicate
with a lambda expression to test if a number is even:
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
Predicate<Integer> isEven = (n) -> (n % 2 == 0);
System.out.println(isEven.test(4)); // true
System.out.println(isEven.test(5)); // false
}
}
You can use the default methods and
, or
, and negate
to chain predicates.
import java.util.function.Predicate;
public class PredicateChainingExample {
public static void main(String[] args) {
Predicate<String> isNotNull = (s) -> s != null;
Predicate<String> isNotEmpty = (s) -> !s.isEmpty();
Predicate<String> isShortString = (s) -> s.length() < 5;
Predicate<String> combinedPredicate = isNotNull.and(isNotEmpty).and(isShortString);
System.out.println(combinedPredicate.test("Test")); // true
System.out.println(combinedPredicate.test("")); // false
System.out.println(combinedPredicate.test(null)); // false
System.out.println(combinedPredicate.test("This is a long string")); // false
}
}
Predicates are particularly useful when working with collections. They can be used to filter collections using the Stream
API.
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class FilterExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Jack", "Doe");
Predicate<String> startsWithJ = (s) -> s.startsWith("J");
List<String> filteredNames = names.stream()
.filter(startsWithJ)
.collect(Collectors.toList());
System.out.println(filteredNames); // [John, Jane, Jack]
}
}
Predicate
interface provides default methods for composing complex predicates, making it flexible to use.Consider a scenario where you have a list of users, and you want to filter out those who are adults and have active accounts.
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
class User {
private String name;
private int age;
private boolean active;
public User(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
public int getAge() {
return age;
}
public boolean isActive() {
return active;
}
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + ", active=" + active + "}";
}
}
public class UserFilterExample {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("John", 25, true),
new User("Jane", 17, true),
new User("Jack", 30, false),
new User("Doe", 22, true)
);
Predicate<User> isAdult = (u) -> u.getAge() >= 18;
Predicate<User> isActive = (u) -> u.isActive();
List<User> filteredUsers = users.stream()
.filter(isAdult.and(isActive))
.collect(Collectors.toList());
filteredUsers.forEach(System.out::println);
}
}
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
class User {
private String name;
private int age;
private boolean active;
public User(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
public int getAge() {
return age;
}
public boolean isActive() {
return active;
}
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + ", active=" + active + "}";
}
}
public class UserFilterExample {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("John", 25, true),
new User("Jane", 17, true),
new User("Jack", 30, false),
new User("Doe", 22, true)
);
Predicate<User> isAdult = (u) -> u.getAge() >= 18;
Predicate<User> isActive = (u) -> u.isActive();
List<User> filteredUsers = users.stream()
.filter(isAdult.and(isActive))
.collect(Collectors.toList());
filteredUsers.forEach(System.out::println);
}
}
In this example, isAdult
and isActive
are predicates that are combined using and
to filter the list of users.
By using the Predicate
interface and lambda expressions, you can write clean, concise, and expressive code for evaluating conditions and processing collections.