[EN] Java Predicate Chain

Julian | Jul 23, 2024 min read

1. What is a Predicate?

A Predicate is a functional interface in Java 8 that checks a condition and returns a boolean DayOfWeek returns: true or false. It has a single abstract method:

@FunctionalInterface 
public interface Predicate<T> { 
boolean test(T t); 
} 

This means that a Predicate is used to apply a condition to an input of type T and check whether it is satisfied.

2. Simple example of Predicate

Here is a simple example to demonstrate how a Predicate works:

Predicate<Integer> isEven = n -> n % 2 == 0; // Checks whether a number is even 

System.out.println(isEven.test(4)); // true 
System.out.println(isEven.test(5)); // false 

3. Combine Predicates

Java 8 allows you to combine predicates. There are three main ways to do this:

  • and(): Combines two predicates and returns true if both predicates are true.
  • or(): Combines two predicates and returns true if at least one of the predicates is true.
  • negate(): Returns a Predicate that is the opposite of a given Predicate.

4. Predicate chaining: AND example

The and() method allows two predicates to be combined so that the condition is only met if both predicates return true:

Predicate<Integer> isPositive = n -> n > 0; 
Predicate<Integer> isEven = n -> n % 2 == 0; 

Predicate<Integer> isPositiveAndEven = isPositive.and(isEven); 

System.out.println(isPositiveAndEven.test(4)); // true 
System.out.println(isPositiveAndEven.test(-4)); // false 
System.out.println(isPositiveAndEven.test(5)); // false 

5. Predicate chaining: OR example

The or() method allows two predicates to be combined so that the condition is satisfied if at least one of the predicates returns true:

Predicate<Integer> isNegative = n -> n < 0; 
Predicate<Integer> isEven = n -> n % 2 == 0; 

Predicate<Integer> isNegativeOrEven = isNegative.or(isEven); 

System.out.println(isNegativeOrEven.test(4)); // true 
System.out.println(isNegativeOrEven.test(-5)); // true 
System.out.println(isNegativeOrEven.test(5)); // false 

6. Predicate chaining: NEGATE example

The negate() method returns a Predicate that is the opposite of a given Predicate:

Predicate<Integer> isPositive = n -> n > 0; 

Predicate<Integer> isNotPositive = isPositive.negate(); 

System.out.println(isNotPositive.test(4)); // false 
System.out.println(isNotPositive.test(-4)); // true 

7. More complex examples and applications

One can combine these methods to create more complex logical conditions:

Predicate<String> isNotNull = Objects::nonNull; 
Predicate<String> isNotEmpty = s -> !s.isEmpty(); 
Predicate<String> hasLengthOf5 = s -> s.length() == 5; 

Predicate<String> complexPredicate = isNotNull.and(isNotEmpty).and(hasLengthOf5); 

System.out.println(complexPredicate.test("Hello")); // true 
System.out.println(complexPredicate.test("Hi")); // false 
System.out.println(complexPredicate.test("")); // false 
System.out.println(complexPredicate.test(null)); // false 

8. Use in streams

Predicates are particularly useful in combination with Java Streams as they can be used to filter data:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, -1, -2, -3); 

List<Integer> positiveNumbers = numbers.stream() 
.filter(isPositive) 
.collect(Collectors.toList()); 

System.out.println(positiveNumbers); // [1, 2, 3, 4, 5] 

9. Best Practices

  • Readability: Chain only as many predicates as necessary to ensure the readability of your code.
  • Reusability: Define predicates as separate variables and combine them to be reusable.
  • Debugging: Use meaningful names for your predicates to make debugging easier.

With this basic knowledge of predicates and their possible combinations, you should be able to use 80% of the functionalities in practical applications. Good luck using Predicate Chains in your projects!