Functional Interfaces Review — BiPredicate
The BiPredicate interface in Java is similar to the Predicate interface, but it takes two input arguments instead of one. It is a part of the java.util.function package and represents a predicate (boolean-valued function) of two arguments. Here’s everything you need to know about the BiPredicate interface, along with examples:
Definition
The BiPredicate interface is defined as follows:
@FunctionalInterface
public interface BiPredicate<T, U> {
boolean test(T t, U u);
default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> other) {
Objects.requireNonNull(other);
return (t, u) -> test(t, u) && other.test(t, u);
}
default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> other) {
Objects.requireNonNull(other);
return (t, u) -> test(t, u) || other.test(t, u);
}
default BiPredicate<T, U> negate() {
return (t, u) -> !test(t, u);
}
}Methods
- test(T t, U u): This is the single abstract method of the
BiPredicateinterface. It evaluates the predicate on the given arguments and returns a boolean value. - and(BiPredicate<? super T, ? super U> other): This is a default method that returns a composed predicate that represents a short-circuiting logical AND of this predicate and another.
- or(BiPredicate<? super T, ? super U> other): This is a default method that returns a composed predicate that represents a short-circuiting logical OR of this predicate and another.
- negate(): This is a default method that returns a predicate that represents the logical negation of this predicate.
Key Points
- Since
BiPredicateis a functional interface, it can be implemented using lambda expressions or method references. BiPredicateis often used for filtering or matching pairs of objects based on a condition.
Usage Examples
Basic Example
Here’s a simple example of how to use the BiPredicate interface:
import java.util.function.BiPredicate;Get Full Stack Developer’s stories in your inbox
Join Medium for free to get updates from this writer.
public class BiPredicateExample {
public static void main(String[] args) {
// Define a BiPredicate that checks if the sum of two numbers is greater than 10
BiPredicate<Integer, Integer> sumGreaterThanTen = (a, b) -> (a + b) > 10;
// Use the BiPredicate
System.out.println(sumGreaterThanTen.test(5, 7)); // true
System.out.println(sumGreaterThanTen.test(3, 4)); // false
}
}
Chaining BiPredicates
You can chain multiple BiPredicate instances using the and, or, and negate methods:
import java.util.function.BiPredicate;
public class BiPredicateChainingExample {
public static void main(String[] args) {
// Define two BiPredicates
BiPredicate<String, String> isEqual = String::equals;
BiPredicate<String, String> isNotNull = (s1, s2) -> s1 != null && s2 != null;
// Chain the BiPredicates
BiPredicate<String, String> combinedPredicate = isNotNull.and(isEqual);
// Use the combined BiPredicate
System.out.println(combinedPredicate.test("Hello", "Hello")); // true
System.out.println(combinedPredicate.test(null, "Hello")); // false
}
}Using Method References
You can also use method references with BiPredicate:
import java.util.function.BiPredicate;
import java.util.Map;
public class MethodReferenceExample {
public static void main(String[] args) {
// Define a BiPredicate using a method reference
BiPredicate<Map<String, String>, String> containsKey = Map::containsKey;
// Use the BiPredicate with a Map
Map<String, String> map = Map.of("Alice", "Engineer", "Bob", "Manager");
System.out.println(containsKey.test(map, "Alice")); // true
System.out.println(containsKey.test(map, "Charlie")); // false
}
}Using BiPredicate with Collections
You can use BiPredicate to filter pairs of elements in collections:
import java.util.List;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
public class ListBiPredicateExample {
public static void main(String[] args) {
List<String> words = List.of("Apple", "Banana", "Cherry", "Date");
List<Integer> lengths = List.of(5, 6, 6, 4);
// Define a BiPredicate that checks if a word has the specified length
BiPredicate<String, Integer> hasLength = (word, length) -> word.length() == length;
// Use the BiPredicate to filter the lists
List<String> filteredWords = words.stream()
.filter(word -> lengths.stream().anyMatch(length -> hasLength.test(word, length)))
.collect(Collectors.toList());
System.out.println(filteredWords); // [Apple, Banana, Date]
}
}Practical Use Cases
- Filtering Collections:
BiPredicatecan be used to filter elements in collections based on conditions involving two arguments. - Conditional Checks: Used for conditional checks that involve two parameters.
- Validation: Can be used for validating pairs of inputs.
- Event Handling: Used to handle events that involve two pieces of data.
Summary
The BiPredicate interface is a functional interface in Java that represents a condition or a boolean-valued function of two arguments. It is useful for filtering and matching purposes involving pairs of objects, and it can be implemented using lambda expressions and method references. The interface also provides methods for logical operations (and, or, negate). BiPredicate is a versatile tool in functional programming, particularly in contexts where two inputs need to be evaluated together.







