BiPredicate Functional Interface in Java

BiPredicate interface in Java is an extension of the Predicate interface.  It has one functional method boolean test(T t, U u), which accepts two inputs and returns a boolean value.

Since it is a Functional Interface, we can implement it with a Lambda expression.

BiPredicate<T, U>

@FunctionalInterface
public interface BiPredicate<T, U> {
    /**
     * Evaluates this predicate on the given arguments.
     *
     * @param t the first input argument
     * @param u the second input argument
     * @return {@code true} if the input arguments match the predicate,
     * otherwise {@code false}
     */
    boolean test(T t, U u);

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * AND of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code false}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ANDed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * AND of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> other) {
        Objects.requireNonNull(other);
        return (T t, U u) -> test(t, u) && other.test(t, u);
    }

    /**
     * Returns a predicate that represents the logical negation of this
     * predicate.
     *
     * @return a predicate that represents the logical negation of this
     * predicate
     */
    default BiPredicate<T, U> negate() {
        return (T t, U u) -> !test(t, u);
    }

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * OR of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code true}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ORed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * OR of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> other) {
        Objects.requireNonNull(other);
        return (T t, U u) -> test(t, u) || other.test(t, u);
    }
}


T represents the type of the first argument, and U represents the type of the second argument.

As you can see, in addition to the single abstract method, there are three default methods.

NoteAll other methods must be followed by a call to the test() method to pass the parameters.

Implementing the BiPredicate interface

Example 1:

class Test {

  public static void main(String[] args) {
    BiPredicate<String, Integer> biPredicate = (str, num) -> str.equals("alegrucoding") && num > 5;
    System.out.println(biPredicate.test("alegrucoding", 3));
  }
}
Output: false
 
Here, inside the braces <>, we specified what types are the inputs, and we used a Lambda expression to write the implementation of the BiPredicate interface. 

Between the parentheses (), we have the input parameters, and on the right side of the arrow sign (->), we wrote the logic.

Note: If we have a single statement inside the Lambda body, then we don’t need to put the curly braces {}.
The same for the input parameter, if we are dealing with only one, we don’t need to put it between the parentheses ().
Also, if we have a single statement that returns some result, we don’t have to put the return keyword, it would be redundant.

Here, we have two input parameters, so we put them between the parentheses ().

We called here the single abstract (functional) method test(), and we passed two parameters, one as a string and the other as a number.

Example 2:

Implementation of the and(BiPredicate<? super T, ? super U> other) method that accepts the BiPredicate and returns the BiPredicate also. 

class Test {

  public static void main(String[] args) {
    BiPredicate<Integer, Integer> biPredicate1 = (num1, num2) -> num1 > 5 && num2 > 5;
    BiPredicate<Integer, Integer> biPredicate2 = (num1, num2) -> num1 % 2 == 0 && num2 % 2 == 0;

    System.out.println(biPredicate1.and(biPredicate2).test(10, 7));
  }
}
Output: false

Here we used the and() method to chain the BiPredicates. The and() method acts as the short-circuiting logical AND operator. It will return true only if both BiPredicates return true.

In the example above, we got false because the biPredicate2 returns false.

We needed to call the test() method to pass the two parameters.

Example 3:

Implementation of the BiPredicate<T, U> negate() method that does not accept any inputs and returns the BiPredicate interface. 

class Test {

  public static void main(String[] args) {
    BiPredicate<Integer, Integer> biPredicate1 = (num1, num2) -> num1 > 5 && num2 > 5;
    BiPredicate<Integer, Integer> biPredicate2 = (num1, num2) -> num1 % 2 == 0 && num2 % 2 == 0;

    System.out.println(biPredicate1.and(biPredicate2).negate().test(10, 7));
  }
}
Output: true
 
Here, we used the same program as before. We added the call to the negate() method and got a different result this time because the negate() method will negate the result returned from both BiPredicates.
It converts true to false and vice versa.

Example 4:

Implementation of the or(BiPredicate<? super T, ? super U> other) method that accepts the BiPredicate and returns the BiPredicate also. Like the and(BiPredicate<? super T, ? super U> other) method. The difference is that or() method returns true if any of the BiPredicates return true.

class Test {

  public static void main(String[] args) {
    BiPredicate<String, String> biPredicate1 = (str1, str2) -> str1.equals("alegrucoding") && str2.equals("blog");
    BiPredicate<String, String> biPredicate2 = (num1, num2) -> num1.length() == num2.length();

    System.out.println(biPredicate1.or(biPredicate2).test("alegrucoding", "blog"));
  }
}
Output: true
 
Here, we got true since the biPredicate1 returns true.
 
That was all about the BiPredicate interface in Java. Proceed to the next lesson.
 
Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *