ZetCode

Java Predicate

last modified January 10, 2023

Java Predicate tutorial shows 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

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.

Java Predicate

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.

com/zetcode/JavaPredicateEx.java
package com.zetcode;

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;
    }
}

public class JavaPredicateEx {

    public static void main(String[] args) {

        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 JavaPredicateEx.java
6
7
8
9
12

Java Predicate with lambda

Java lambda expression simplifies the creation of Java Predicates.

com/zetcode/JavaPredicateEx2.java
package com.zetcode;

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

public class JavaPredicateEx2 {

    public static void main(String[] args) {

        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.

Java Predicate removeIf

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

com/zetcode/ListRemoveIf.java
package com.zetcode;

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

public class ListRemoveIf {

    public static void main(String[] args) {

        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 ListRemoveIf.java
[warm, winter, cloud, tree, silk]

Java Predicate Collectors.PartitioningBy

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

com/zetcode/CollectorsPartitioningBy.java
package com.zetcode;

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

public class CollectorsPartitioningBy {

    public static void main(String[] args) {

        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 CollectorsPartitioningBy.java
[4, 1, 2, 3]
[-3, -1, -2, -1]
[[-3, -1, -2, -1], [4, 1, 2, 3]]

Java Pattern.asMatchPredicate

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

com/zetcode/AsMatchPredicate.java
package com.zetcode;

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

public class AsMatchPredicate {

    public static void main(String[] args) {

        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 AsMatchPredicate.java 
book
bookworm
bookkeeper
bookmark

Java Predicate Stream.allMatch

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

com/zetcode/StreamAllMatch.java
package com.zetcode;

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

public class StreamAllMatch {

    public static void main(String[] args) {

        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 StreamAllMatch.java
All values of collection values1 are positive
All values of collection values2 are not positive

Java 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.

com/zetcode/AsPredicate.java
package com.zetcode;

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

public class AsPredicate {

    public static void main(String[] args) {

        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 AsPredicate.java 
There is a word which has three latin characters

Java Predicate Stream.Iterate

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.

com/zetcode/StreamIterate.java
package com.zetcode;

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

public class StreamIterate {

    public static void main(String[] args) {

        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 StreamIterate.java
1.0
2.0
4.0
8.0
16.0
32.0
64.0

Java Predicate multiple conditions

The next example uses a predicate with two conditions.

com/zetcode/JavaMulCond.java
package com.zetcode;

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

public class JavaMulCond {

    public static void main(String[] args) {

        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 JavaMulCond.java
Country{name=Iran, population=80840713}
Country{name=India, population=1342512000}

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

Java Predicate.isEqual​

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

com/zetcode/PredicateIsEqual.java
package com.zetcode;

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

public class PredicateIsEqual {

    public static void main(String[] args) {

        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");
        }
    }

    public record User(String name, String occupation) {
    }
}

The example checks if two lists of users are equal.

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

Java IntPredicate

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

com/zetcode/IntPredicateEx.java
package com.zetcode;

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

public class IntPredicateEx {

    public static void main(String[] args) {
        
        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.

Java BiPredicate

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

com/zetcode/BiPredicateEx.java
package com.zetcode;

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

public class BiPredicateEx {

    public static void main(String[] args) {

        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 BiPredicateEx.java
sky
spy
war
cup
see
---------------------
club
silk
coin
snow

Composing predicates

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

com/zetcode/JavaPredicateCompose.java
package com.zetcode;

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

public class JavaPredicateCompose {

    public static void main(String[] args) {

        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 JavaPredicateCompose.java
5
6
7
8
**********
6
9

Java apply list of predicates

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

com/zetcode/ListOfPredicates.java
package com.zetcode;

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

public class ListOfPredicates {

    public static void main(String[] args) {

        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 ListOfPredicates.java 
sky
shy
way
spy
sly
wry
why

Java Predicate with method reference

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

com/zetcode/PredicateMethodReference.java
package com.zetcode;

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

public class PredicateMethodReference {

    public static void main(String[] args) {

        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.

com/zetcode/JavaPredicateNegate.java
package com.zetcode;

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

public class JavaPredicateNegate {

    public static void main(String[] args) {

        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 JavaPredicateNegate.java
6
7
8
9
12
**********
2
3
1
5

Java predicate as method parameter

Predicates can be passed as method parameters.

com/zetcode/PredicateMethodParam.java
package com.zetcode;

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

public class PredicateMethodParam {

    public static void main(String args[]) {

        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);
    }

    private static 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.

In this article, we have worked with Java Predicates.

List all Java tutorials.