ZetCode

Java Predicate

last modified February 24, 2024

In this article we show how to use predicates in Java. With predicates, we can create code that is more clean and readable. Predicates also help to create better tests.

Predicate definition

Predicate in general meaning is a statement about something that is either true or false. In programming, predicates represent single argument functions that return a boolean value.

The Predicate interface

Predicates in Java are implemented with interfaces. Predicate<T> is a generic functional interface representing a single argument function that returns a boolean value. It is located in the java.util.function package. It contains a test(T t) method that evaluates the predicate on the given argument.

In Java we do not have standalone functions. Furthermore, methods are not first-class citizens. (They cannot be added to collections or passed to methods as parameters.) Therefore, we define interfaces and create objects from these interfaces. Such objects can be then passed to methods such as Iterables.filter. With Java lambdas it is much easier to work with predicates.

Java Predicate example

The following example creates a simple Java Predicate.

Main.java
import java.util.List;
import java.util.function.Predicate;

class BiggerThanFive<E> implements Predicate<Integer> {

    @Override
    public boolean test(Integer v) {

        Integer five = 5;

        return v > five;
    }
}

void main() {

    List<Integer> nums = List.of(2, 3, 1, 5, 6, 7, 8, 9, 12);

    BiggerThanFive<Integer> btf = new BiggerThanFive<>();
    nums.stream().filter(btf).forEach(System.out::println);
}

In the example, the predicate is used to filter integers.

class BiggerThanFive<E> implements Predicate<Integer> {

    @Override
    public boolean test(Integer v) {

        Integer five = 5;

        return v > five;
    }
}

This is a Java class implementing the Predicate<Integer> interface. Its test method returns true for values bigger than five.

List<Integer> nums = List.of(2, 3, 1, 5, 6, 7, 8, 9, 12);

We have a list of integer values.

BiggerThanFive<Integer> btf = new BiggerThanFive<>();

A BiggerThanFive is instantiated.

nums.stream().filter(btf).forEach(System.out::println);

The predicate object is passed to the filter method to get all values from the list that are bigger than five.

$ java Main.java
6
7
8
9
12

Java Predicate with lambda

Java lambda expression simplifies the creation of Java Predicates.

Main.java
import java.util.List;
import java.util.function.Predicate;

void main() {

    List<Integer> nums = List.of(2, 3, 1, 5, 6, 7, 8, 9, 12);

    Predicate<Integer> btf = n -> n > 5;

    nums.stream().filter(btf).forEach(System.out::println);
}

The example filters integer values; this time we use Java lambda expression, which makes the code much shorter.

Predicate<Integer> btf = n -> n > 5;

This is a one-liner that creates the predicate.

The ArrayList removeIf method

The ArrayList's removeIf method removes all all elements that satisfy the given predicate.

Main.java
import java.util.ArrayList;
import java.util.function.Predicate;

void main() {

    var words = new ArrayList<String>();
    words.add("sky");
    words.add("warm");
    words.add("winter");
    words.add("cloud");
    words.add("pen");
    words.add("den");
    words.add("tree");
    words.add("sun");
    words.add("silk");

    Predicate<String> hasThreeChars = word -> word.length() == 3;
    words.removeIf(hasThreeChars);

    System.out.println(words);
}

We have a list of words. We remove all words from the list that have three latin characters.

$ java Main.java
[warm, winter, cloud, tree, silk]

The Collectors.PartitioningBy method

The Collectors.PartitioningBy returns a Collector which partitions the input elements according to a Predicate, and organizes them into a Map<Boolean, List<T>>.

Main.java
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

void main() {

    var values = List.of(3, -1, 2, 4, -1, 1, 2, 3);

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

    Map<Boolean, List<Integer>> groups = values.stream()
            .collect(Collectors.partitioningBy(isPositive));

    System.out.println(groups.get(true));
    System.out.println(groups.get(false));

    List<List<Integer>> subSets = new ArrayList<>(groups.values());
    System.out.println(subSets);
}

We have a list of integers. The list is partitioned into two sublists: positive values and negative values.

$ java Main.java
[4, 1, 2, 3]
[-3, -1, -2, -1]
[[-3, -1, -2, -1], [4, 1, 2, 3]]

Pattern.asMatchPredicate

The Pattern.asMatchPredicate creates a predicate that tests if a pattern matches the given input string.

Main.java
import java.util.List;
import java.util.regex.Pattern;

void main() {

    var words = List.of("book", "bookshelf", "bookworm",
            "bookcase", "bookish", "bookkeeper", "booklet", "bookmark");

    var pred = Pattern.compile("book(worm|mark|keeper)?").asMatchPredicate();
    words.stream().filter(pred).forEach(System.out::println);
}

We create predicate from a regex pattern with Pattern.asMatchPredicate and apply it to the filter method.

$ java Main.java
book
bookworm
bookkeeper
bookmark

The Stream.allMatch predicate

The Stream.allMatch method returns a boolean value indicating whether all elements of the stream match the provided predicate.

Main.java
import java.util.List;
import java.util.function.Predicate;

void main() {

    var values1 = List.of(1, 5, 3, 2, 8, 6, 7);
    var values2 = List.of(1, 5, 3, -2, 8, 0, 9);

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

    var res1 = values1.stream().allMatch(isPositive);

    if (res1) {
        System.out.println("All values of collection values1 are positive");
    } else {
        System.out.println("All values of collection values1 are not positive");
    }

    var res2 = values2.stream().allMatch(isPositive);

    if (res2) {
        System.out.println("All values of collection values2 are positive");
    } else {
        System.out.println("All values of collection values2 are not positive");
    }
}

In the example, we check if all the values of two collections have only positive values.

$ java Main.java
All values of collection values1 are positive
All values of collection values2 are not positive

Pattern.asPredicate

The Pattern.asPredicate method creates a predicate that tests if this pattern is found in a given input string. The Stream.AnyMatch method returns a boolean value indicating whether any elements of the stream match the provided predicate.

Main.java
import java.util.List;
import java.util.regex.Pattern;

void main() {

    var words = List.of("skylark", "trial", "water", "cloud", "curtain", "falcon");

    var pred = Pattern.compile("^...{3}$").asPredicate();
    var res = words.stream().anyMatch(pred);

    if (res) {
        System.out.println("There is a word which has three latin characters");
    } else {
        System.out.println("There is no word which has three latin characters");
    }
}

We have a list of words. We check if there is a word that has three latin characters.

$ java Main.java
There is a word which has three latin characters

The Stream.Iterate method

The Stream.Iterate method returns a sequential ordered stream produced by iterative application of the given function to an initial element, conditioned on satisfying the given predicate.

Main.java
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

void main() {

    Predicate<Double> pred = e -> e < 100;
    UnaryOperator<Double> op = e -> e * 2;

    Stream.iterate(1d, pred, op).forEach(System.out::println);
}

With Stream.iterate, we generate a stream which applies the given function to the previosly generated element. The stream terminates when the predicate returns false; in our case, when the generated stream value is greater than 100.

$ java Main.java
1.0
2.0
4.0
8.0
16.0
32.0
64.0

Predicate with multiple conditions

The next example uses a predicate with two conditions.

Main.java
import java.util.List;
import java.util.function.Predicate;

void main() {

    var countries = List.of(
            new Country("Iran", 80840713),
            new Country("Hungary", 9845000),
            new Country("Poland", 38485000),
            new Country("India", 1342512000),
            new Country("Latvia", 1978000),
            new Country("Vietnam", 95261000),
            new Country("Sweden", 9967000),
            new Country("Iceland", 337600),
            new Country("Israel", 8622000));

    Predicate<Country> p1 = c -> c.name().startsWith("I") &&
            c.population() > 10000000;

    countries.stream().filter(p1).forEach(System.out::println);
}

record Country(String name, int population) {
}

In the example, we create a list of countries. We filter the list by the country name and population.

Predicate<Country> p1 = c -> c.name().startsWith("I") &&
    c.population() > 10000000;

The predicate returns true for countries that start with 'I' and their population is over ten million.

$ java Main.java
Country{name=Iran, population=80840713}
Country{name=India, population=1342512000}

Two countries from the list fulfill the conditions: Iran and India.

The Predicate.isEqual method

The Predicate.isEqual returns a predicate that tests if two arguments are equal according to Objects.equals.

Main.java
import java.util.List;
import java.util.function.Predicate;

void main() {

    var users1 = List.of(new User("John Doe", "gardener"),
            new User("Roger Roe", "driver"), new User("Jane Doe", "teacher"));

    var users2 = List.of(new User("John Doe", "gardener"),
            new User("Roger Roe", "driver"), new User("Jane Doe", "teacher"));

    var users3 = List.of(new User("John Doe", "architect"),
            new User("Roger Roe", "driver"), new User("Jane Doe", "teacher"));

    Predicate<List<User>> pred = Predicate.isEqual(users1);

    if (pred.test(users2)) {
        System.out.println("users1 and user2 are equal");
    } else {
        System.out.println("users1 and user2 are not equal");
    }

    if (pred.test(users3)) {
        System.out.println("users1 and user3 are equal");
    } else {
        System.out.println("users1 and user3 are not equal");
    }
}

record User(String name, String occupation) {
}

The example checks if two lists of users are equal.

$ java Main.java
users1 and user2 are equal
users1 and user3 are not equal

IntPredicate

IntPredicate represents a predicate of one int-valued argument. This is the int-consuming primitive type specialization of Predicate<E>.

Main.java
import java.util.Arrays;
import java.util.function.IntPredicate;

void main() {

    int[] nums = { 2, 3, 1, 5, 6, 7, 8, 9, 12 };
    IntPredicate p = n -> n > 5;

    Arrays.stream(nums).filter(p).forEach(System.out::println);
}

The example filters an array of int values with filter and IntPredicate.

int nums[] = { 2, 3, 1, 5, 6, 7, 8, 9, 12 };

We define an array of integers.

IntPredicate p = n -> n > 5;

An IntPredicate is created; it returns true for int values bigger than five.

Arrays.stream(nums).filter(p).forEach(System.out::println);

We create a stream from the array and filter the elemetnts. The filter method receives the predicate as a parameter.

BiPredicate

The BiPredicate is the two-arity specialization of Predicate. It represents a predicate of two arguments.

Main.java
import java.util.List;
import java.util.function.BiPredicate;

void main() {

    var words = List.of("sky", "water", "club", "spy", "silk", "summer",
            "war", "cup", "cloud", "coin", "small", "terse", "falcon",
            "snow", "snail", "see");

    BiPredicate<String, Integer> pred = (w, len) -> w.length() == len;
    words.stream().filter(e -> pred.test(e, 3)).forEach(System.out::println);

    System.out.println("---------------------");

    words.stream().filter(e -> pred.test(e, 4)).forEach(System.out::println);
}

The BiPredicate is used to pick up words which have three and four latin characters.

$ java Main.java
sky
spy
war
cup
see
---------------------
club
silk
coin
snow

Composing predicates

With and and or methods we can compose predicates in Java.

Main.java
import java.util.Arrays;
import java.util.function.IntPredicate;

void main() {

    int[] nums = {2, 3, 1, 5, 6, 7, 8, 9, 12};

    IntPredicate p1 = n -> n > 3;
    IntPredicate p2 = n -> n < 9;

    Arrays.stream(nums).filter(p1.and(p2)).forEach(System.out::println);

    System.out.println("-------------------");

    IntPredicate p3 = n -> n == 6;
    IntPredicate p4 = n -> n == 9;

    Arrays.stream(nums).filter(p3.or(p4)).forEach(System.out::println);
}

The example filters data using composition of IntPredicates.

IntPredicate p1 = n -> n > 3;
IntPredicate p2 = n -> n < 9;

Arrays.stream(nums).filter(p1.and(p2)).forEach(System.out::println);

We combine two predicates with the and method; we get integers that are bigger than three and smaller than nine.

IntPredicate p3 = n -> n == 6;
IntPredicate p4 = n -> n == 9;

Arrays.stream(nums).filter(p3.or(p4)).forEach(System.out::println);

With the or method, we get values that are equal either to six or nine.

$ java Main.java
5
6
7
8
-------------------
6
9

Applying list of predicates

In the following example, we work with a list of predicates.

Main.java
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

void main() {

    var words = List.of("sky", "curtain", "sin", "shy", "way", "club",
            "spy", "silk", "summer", "war", "cup", "cloud", "coin", "small",
            "set", "terse", "tree", "sea", "sip", "snow", "snail", "sly",
            "six", "sod", "see", "sit", "sad", "wry", "why");

    Predicate<String> p1 = e -> e.startsWith("s") || e.startsWith("w");
    Predicate<String> p2 = e -> e.endsWith("y");
    Predicate<String> p3 = e -> e.length() == 3;

    var prs = List.of(p1, p2, p3);

    var result = words.stream()
            .filter(prs.stream().reduce(x -> true, Predicate::and))
            .collect(Collectors.toList());

    result.forEach(System.out::println);
}

With the help of the reduce method, we apply the list of predicates to the list of words.

$ java Main.java
sky
shy
way
spy
sly
wry
why

Predicate with a method reference

Predicates can be created easily with method references. These are created with :: operator.

Main.java
import java.util.List;
import java.util.function.Predicate;

void main() {

    var words = List.of("sky", "", "club", "spy", "silk", "summer",
            "war", "cup", "cloud", "coin", "small", "terse", "",
            "snow", "snail", "see");

    Predicate<String> pred = String::isEmpty;

    var res = words.stream().anyMatch(pred);

    if (res) {
        System.out.println("There is an empty string");
    } else {
        System.out.println("There is no empty string");
    }
}

The example checks if there is any empty string in the list.

Negating predicates

The negate method returns a predicate that represents the logical negation of the given predicate.

Main.java
import java.util.Arrays;
import java.util.function.IntPredicate;

void main() {

    int[] nums = {2, 3, 1, 5, 6, 7, 8, 9, 12};

    IntPredicate p = n -> n > 5;

    Arrays.stream(nums).filter(p).forEach(System.out::println);

    System.out.println("-----------------");

    Arrays.stream(nums).filter(p.negate()).forEach(System.out::println);
}

The example demonstrates the usage of the negate method.

IntPredicate p = n -> n > 5;

We have a predicate that returns true for values bigger than five.

Arrays.stream(nums).filter(p).forEach(System.out::println);

We filter all integers that are bigger than five.

Arrays.stream(nums).filter(p.negate()).forEach(System.out::println);

With the negate method, we get the opposite: values lower or equal to four.

$ java Main.java
6
7
8
9
12
-----------------
2
3
1
5

Alternatively, we can use the Predicate.not method.

Main.java
import java.util.List;
import java.util.function.Predicate;

void main() {

    var words = List.of("book", "cup", "tree", "town", "sky", "by",
            "call", "ten", "top", "smart", "park");

    Predicate<String> hasThreeChars = (String word) -> word.length() == 3;

    var res = words.stream().filter(hasThreeChars).toList();
    System.out.println(res);

    var res2 = words.stream().filter(Predicate.not(hasThreeChars)).toList();
    System.out.println(res2);
}

In the program, we define a list of words. The defined predicate returns true for all words that contain three latin characters. The Predicate.not(hasThreeChars) returns the opposite: all words that have less or more latin characters.

$ java Main.java
[cup, sky, ten, top]
[book, tree, town, call, smart, park]

Predicate as a method parameter

Predicates can be passed as method parameters.

Main.java
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

void main() {

    List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7,
            8, 9, 10, 11, 12);

    List<Integer> all = eval(list, n -> true);
    System.out.println(all);

    List<Integer> evenValues = eval(list, n -> n % 2 == 0);
    System.out.println(evenValues);

    List<Integer> greaterThanSix = eval(list, n -> n > 6);
    System.out.println(greaterThanSix);
}

List<Integer> eval(List<Integer> values,
        Predicate<Integer> predicate) {
    return values.stream().filter(predicate)
            .collect(Collectors.toList());
}

In the example, we pass a predicate function as the second parameter to the eval method.

Source

Java Predicate - language reference

In this article we have worked with Java Predicates.

Author

My name is Jan Bodnar and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.

List all Java tutorials.