Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Deferred Execution With Java's Predicate

DZone's Guide to

Deferred Execution With Java's Predicate

Check out this post on using the Predicate method in JDK, as well as how to determine if Optional applies. Click here to read more!

· Java Zone ·
Free Resource

FlexNet Code Aware, a free scan tool for developers. Scan Java, NuGet, and NPM packages for open source security and open source license compliance issues.

In the previous posts "Deferred Execution with Java's Supplier" and "Deferred Execution with Java's Consumer," I looked at easily deferring execution in Java via standard Java APIs that accept, respectively, Suppliers and Consumers. In this post, I take a similar look at how standard JDK-provided APIs allow for deferred execution via the standard functional interface Predicate. The Predicate is described in its Javadoc: "Represents a predicate (boolean-valued function) of one argument." In other words, a Predicateis like a JDK-supplied Function, but its return value is limited to either true or false.

Perhaps, the most common application of Predicate in the standard Java APIs is in the context of filters. Several of the examples in this post will demonstrate the use of Predicate in conjunction with filtering methods on instances of Optional and Stream.

Optional.filter(Predicate)

The behavior of the Optional classfilter(Predicate) method is described by this Javadoc documentation, "If a value is present, and the value matches the given predicate, returns an Optionaldescribing the value, otherwise returns an empty Optional." In other words, Optional.filter(Predicate) returns an Optional that will be empty if either the original Optionalwas empty or if the Predicate applied to the original and present Optional resolves to false. Otherwise, if the original Optional contains a "present" value and the Predicate applied to that value returns true, the returned Optional will also have the same "present" value. This is illustrated in the next code listing (full source is available on GitHub).

Optional.filter(Predicate) Demonstrated

/**
* Demonstrate use of {@code Optional.filter(Predicate)} on an
* {@code Optional<Boolean>}.
*/
public static void demonstrateOptionalFilterOnBoolean()
{
    out.print("\nfalse: ");
    getOptionalBoolean(false).filter(b -> b).ifPresent(out::print);
    out.print("\ntrue: ");
    getOptionalBoolean(true).filter(b -> b).ifPresent(out::print);
    out.print("\nnull: ");
    getOptionalBoolean(null).filter(b -> b).ifPresent(out::print);
}

/**
* Demonstrate use of {@code Optional.filter(Predicate)} on an
* {@code Optional<Float>}.
*/
public static void demonstrateOptionalFilterOnFloat()
{
    out.print("\n3.14: ");
    getOptionalFloat(3.14f).filter(f -> f > 0.0).ifPresent(out::print);
    out.print("\n-2.5: ");
    getOptionalFloat(-2.5f).filter(f -> f > 0.0).ifPresent(out::print);
    out.print("\nnull: ");
    getOptionalFloat(null).filter(f -> f > 0.0).ifPresent(out::print);
}


The two methods in the above code listing demonstrate the use of Optional.filter(Predicate) on a lambda expression that results in a direct boolean result and on a lambda expression that results in a boolean result based on the numerical comparison. In one case, the Predicate is the boolean , and, in the other case, the Predicate is the numeric comparison.

Stream.filter(Predicate)

The Stream interface's method filter(Predicate) works similarly to the Optional classmethod of the same name. The next code listing demonstrates the application of Stream.filter(Predicate).

Stream.filter(Predicate) Demonstrated

/**
* Demonstrates use of {@code Stream.filter(Predicate}}.
*/
public static void demonstrateStreamFilter()
{
    final int maximum = 100;
    out.println("\nThe probable prime numbers between 1 and " + maximum + " are:");
    final Stream<BigInteger> bigIntegers = getConsecutiveBigIntegers(maximum);
    bigIntegers.filter(bi -> bi.isProbablePrime(100)).forEach(pp -> out.println(" " + pp));
}


The above code listing is not intended to demonstrate the best approach to identifying prime numbers in Java. Instead, it's intended to demonstrate how filter(Predicate) can be invoked on a Stream to narrow down elements of that Stream to only those matching the Predicate.

For my next illustration of Stream.filter(Predicate), I use the Pattern class' convenient method asPredicate() to supply the instance of the Predicate to be supplied to both examples using Stream.filter(Predicate).

Stream.filter(Predicate) With Pattern.asPredicate() Demonstrated

/**
* Demonstrates use of {@code Pattern.asPredicate()} to provide
* a {@code Predicate} that can be used with {@code Stream.filter()}.
*/
public static void demonstratePatternAsPredicateInFilter()
{
    final long count
    = getPotentialTelephoneNumbers().stream()
    .filter(PATTERN.asPredicate())
    .peek(out::println)
    .count();
    out.println(count + " valid telephone numbers.");
}


Collection.removeIf(Predicate)

The collection interface specifies (and implements as a default method) the useful method removeIf(Predicate). There are also multiple implementations of Collection that implement their own overridden versions of removeIf(Predicate) that include ArrayDeque.removeIf(Predicate), ArrayList.removeIf(Predicate), and Vector.removeIf(Predicate).

The next code listing demonstrates two examples of Collection.removeIf(Predicate) in action. The first example uses the method Predicate.negate() to negate the expected regular expression pattern so that the elements removed from the collection are those that do NOT match the regular expression. The second example performs similar functionality, but it takes advantage of the JDK 11-introduced 'not' method to perform this negation.

Collection.removeIf(Predicate) With Negated Pattern.asPredicate() Demonstrated

/**
* Demonstrates use of {@code Collection.removeIf(Predicate)}
* in conjunction with {@code Predicate.negate()}.
*/
public static void demonstrateCollectionRemoveIf()
{
    final Set<String> telephoneNumbers = new HashSet<>(getPotentialTelephoneNumbers());
    telephoneNumbers.removeIf(PATTERN.asPredicate().negate());
    out.println(telephoneNumbers);
}

/**
* Demonstrates use of {@code Collection.removeIf(Predicate)}
* in conjunction with JDK 11-introduced {@code Predicate.not()}.
*/
public static void demonstrateCollectionRemoveIfWithJdk11Not()
{
    final Set<String> telephoneNumbers = new HashSet<>(getPotentialTelephoneNumbers());
    telephoneNumbers.removeIf(not(PATTERN.asPredicate()));
    out.println(telephoneNumbers);
}


Stream.allMatch(Predicate)

The Stream interface's method allMatch(Predicate) returns true if every single element in the stream matches the provided Predicate. If even a single element does not match the Predicate, the method returns false.

Stream.allMatch(Predicate) Demonstrated

/**
* Demonstrate use of {@code Stream.allMatch(Predicate)}.
*/
public static void demonstrateStreamAllMatch()
{
    final Set<String> names = getNames();
    final boolean allNamesSixDigits = names.stream()
    .allMatch(name -> name.length() == 6);
    out.println("Are all names " + names + " six digits? " + allNamesSixDigits);
}


Stream.anyMatch(Predicate)

The Stream.anyMatch(Predicate) method returns true if at least one of its elements matches the Predicate and returns false if none of its elements match the Predicate.

Stream.anyMatch(Predicate) Demonstrated

/**
* Demonstrate use of {@code Stream.anyMatch(Predicate)}.
*/
public static void demonstrateStreamAnyMatch()
{
    final Set<String> names = getNames();
    final boolean anyNamesSixDigits = names.stream()
    .anyMatch(name -> name.length() == 6);
    out.println("Are any names " + names + " six digits? " + anyNamesSixDigits);
}


Stream.noneMatch(Predicate)

The Stream.noneMatch(Predicate) method returns true when no elements in stream match the Predicateand returns false if at least one element in the stream DOES match the Predicate.

Stream.noneMatch(Predicate) Demonstrated

/**
* Demonstrate use of {@code Stream.noneMatch(Predicate)}.
*/
public static void demonstrateStreamNoneMatch()
{
    final Set<String> names = getNames();
    final boolean noNamesSixDigits = names.stream()
    .noneMatch(name -> name.length() == 6);
    out.println("Are no names " + names + " six digits? " + noNamesSixDigits);
    final boolean noNamesFourDigits = names.stream()
    .noneMatch(name -> name.length() == 4);
    out.println("Are no names " + names + " four digits? " + noNamesFourDigits);
}


Collectors.partitioningBy(Predicate)

Although there are several more JDK APIs that usePredicate, I will wrap this post up with the discussion of using Collectors.partitioningBy(Predicate). This interesting method divides all elements in the stream so that it is invoked upon into two groups with one group associated with key Boolean.TRUE (elements that match the Predicate) and the other group associated with the key Boolean.FALSE. Those elements did not match the Predicate. The next code listing takes advantage of this to divide integers up into even and odd numbers.

Collectors.partitioningBy(Predicate) Demonstrated

/**
* Demonstrate use of {@code Collectors.partitioningBy(Predicate)}.
*/
public static void demonstrateCollectorsPartitioningBy()
{
    final Map<Boolean, List<Integer>> evensAndOdds
    = getConsecutiveIntegers(100)
    .collect(Collectors.partitioningBy(integer -> integer % 2 == 0));
    out.println("Evens: " + evensAndOdds.get(Boolean.TRUE));
    out.println("Odds: " + evensAndOdds.get(Boolean.FALSE));
}


I used several "helper" methods in the above code examples that are not shown in this post. These "helper" methods and all of the examples shown in this post are available on GitHub.

Java's standard functional interface Predicate is a specialized version of the fellow, built-in Java functional interface function that arguably deserves its own specialization because the true/false return status is so commonly useful for representing the conditions in which certain functionality applies or does not apply. This post has demonstrated several instances in the JDK where Predicate is used to determine which stream elements apply, whether or not an Optional applies, and to divide stream elements into those that satisfy the predicate and those that do not. Along the way, convenience methods such as Pattern.asPredicate() and Predicate.not() were also demonstrated.

 Scan Java, NuGet, and NPM packages for open source security and license compliance issues. 

Topics:
java ,tutorial ,predicate ,stream.filter ,optional.filter ,collection.removalf

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}