javajava-8generic-lambda

Is it possible to chain predicates with `and` using different type parameter?


I am learning Java 8 lambdas. Can I join two predicates, with different type parameter, using and method in Predicate interface?

This is my code:

Predicate<Integer> pc = (iv) -> iv > 20;
Predicate<String> pL = (is) -> is.length() > 5;
System.out.println("The predicate result for pc is: " + pc.test(25));
System.out.println("===========");
System.out.println("The predicate result with both condition true: " + pc.and(pL.test("abcd")));

Solution

  • No, you can not chain predicates of different types, unless the chained predicate also accepts the type of the original predicate.

    Looking at the signature, you can easily see that:
    and(Predicate<? super T> other)
    or(Predicate<? super T> other)

    You can chain predicates:

    Predicate<Person> isMale = p -> p.isMale();
    Predicate<Person> isAdult = p -> p.age() >= AGE_OF_MATURITY;
    Predicate<Person> isAdultMale = isAdult.and(isMale);
    

    You can only chain predicates that accept at least (thats what the ? super T says) the same type as the original predicate:

    Predicate<Object> hasWeirdHashCode = o -> o.hashCode() == 0;
    Predicate<Person> nonsense = isMale.and(hasWeirdHashCode);
    

    If you want to test different types (A, B), you need to provide them separately:

    Predicate<A> propertyOfA = [...];
    Predicate<B> propertyOfB = [...];
    
    BiPredicate<A,B> propertyOfAnB = (a, b) -> 
        propertyOfA.test(a) && propertyOfB.test(b);
    

    If you need more than two different types, you need to roll your own, custom TriPredicate, QuadPredicate and so on functional interfaces, which should be straight-forward to implement.