Primitive Type Specializations of Predicate<T>
The functional interfaces IntPredicate, LongPredicate, and DoublePredicate evaluate predicates with int, long, and double arguments, respectively, avoiding the overhead of boxing and unboxing of primitive values (see Table 13.5). The primitive type versions are not subinterfaces of the Predicate<T> interface.
Predicate<Integer> isEven = i -> i % 2 == 0; // Operand unboxed.
System.out.println(“2021 is an even number: “
+ isEven.test(2021)); // Argument boxed. false.
IntPredicate isEvenInt = i -> i % 2 == 0; // No unboxing.
System.out.println(“2021 is an even number: “
+ isEvenInt.test(2021)); // No boxing. false.
Each primitive type version also provides methods for negating a predicate and composing predicates using the methods for short-circuiting logical AND and OR operations.
IntPredicate isOddInt = isEvenInt.negate(); // Negating a predicate.
System.out.println(“2020 is an odd number: “
+ isOddInt.test(2020)); // false.
IntPredicate isInRange = i -> -100 <= i && i <= 100; // Range: [-100, 100]
System.out.println(“21 is in range and odd: “
+ isInRange.and(isOddInt).test(21));// true.
Two-Arity Specialization of Predicate<T>: BiPredicate<T, U>
The BiPredicate<T, U> interface is a two-arity specialization of the Predicate<T> interface. From Table 13.5, we see that its functional method test() has the type (T, U) -> boolean—that is, it takes two arguments of type T and U, and returns a boolean value. There are no primitive type specializations of the BiPredicate<T, U> interface. Example 13.5 illustrates defining and using two-arity predicates. The following two-arity predicate tests if an element is a member (or is contained) in a list. The reference filenames refers to a list of file names.
BiPredicate<String, List<String>> isMember
= (element, list) -> list.contains(element);
System.out.println(isMember.test(“X-File4.doc”, filenames)); // true.
The two-arity predicate below determines if a file name has an extension from a specified set of file extensions.
BiPredicate<String, Set<String>> selector = (filename, extensions) ->
extensions.contains(filename.substring(filename.lastIndexOf(‘.’)));
System.out.println(selector.test(“Y-File.pdf”, extSet)); // true.
Determining the file extension is generalized in Example 13.5 to a list of file names using the generic method filterList() which takes three parameters: a list of file names, a set of file extensions, and a two-arity predicate to do the selection. In the method filterList(), for each element in the list, the following method call is executed: selector.test(element, extSet).
The BiPredicate<T, U> interface also defines default methods to compose compound two-arity predicates. As expected, the or() and the and() methods require a two-arity predicate as an argument. A simple example is given in Example 13.5 to check if the product or the sum of two numbers is equal to a given number:
int number = 21;
BiPredicate<Integer, Integer> isProduct = (i, j) -> i * j == number;
BiPredicate<Integer, Integer> isSum = (i, j) -> i + j == number;
System.out.println(isProduct.or(isSum).test(7, 3)); // true.
Example 13.5 Implementing the BiPredicate<T, U> Functional Interface
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiPredicate;
public class BiPredicateClient {
public static void main(String[] args) {
// List with filenames:
List<String> filenames = new ArrayList<>();
filenames.add(“X-File1.pdf”); filenames.add(“X-File2.exe”);
filenames.add(“X-File3.fm”); filenames.add(“X-File4.doc”);
filenames.add(“X-File5.jpg”); filenames.add(“X-File6.jpg”);
System.out.println(“Filenames: ” + filenames);
// BiPredicate for membership in a list.
BiPredicate<String, List<String>> isMember =
(element, list) -> list.contains(element);
System.out.println(isMember.test(“X-File4.doc”, filenames)); // true.
// Set with file extensions:
Set<String> extSet = new HashSet<>();
extSet.add(“.pdf”); extSet.add(“.jpg”);
System.out.println(“Required extensions: ” + extSet);
// BiPredicate to determine if a filename has an extension from a specified
// set of file extensions.
BiPredicate<String, Set<String>> selector = (filename, extensions) ->
extensions.contains(filename.substring(filename.lastIndexOf(‘.’)));
System.out.println(selector.test(“Y-File.pdf”, extSet)); // true.
List<String> result = filterList(filenames, extSet, selector);
System.out.println(“Files with required extensions: ” + result);
int number = 21;
BiPredicate<Integer, Integer> isProduct = (i, j) -> i * j == number;
BiPredicate<Integer, Integer> isSum = (i, j) -> i + j == number;
System.out.println(isProduct.or(isSum).test(7, 3));
}
/**
* Filters a list according to the criteria of the selector.
* @param list List to filter
* @param extSet Set of file extensions
* @param selector BiPredicate that provides the criteria for filtering
* @return List of elements that match the criteria
*/
public static <E, F> List<E> filterList(List<E> list,
Set<F> extSet,
BiPredicate<E, Set<F>> selector) {
List<E> result = new ArrayList<>();
for (E element : list)
if (selector.test(element, extSet))
result.add(element);
return result;
}
}
Output from the program:
Click here to view code image Filenames: [X-File1.pdf, X-File2.exe, X-File3.fm, X-File4.doc, X-File5.jpg, X-
File6.jpg]
true
Required extensions: [.pdf, .jpg]
true
Files with required extensions: [X-File1.pdf, X-File5.jpg, X-File6.jpg]
true