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