2

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")));
Giorgi Tsiklauri
  • 9,715
  • 8
  • 45
  • 66
Sumon Bappi
  • 1,937
  • 8
  • 38
  • 82
  • 1
    Depends on what actually are you trying to achieve there might be alternatives. You cannot chain then specifically since they are defined to be on different types. The signature of `and` would help understand that. – Naman Oct 01 '20 at 03:33
  • @Naman thanks man, I just wanted to know that different type parameter will work for chaining using `and`. So I can't chain them with different types. – Sumon Bappi Oct 01 '20 at 03:46
  • If the integer and string predicates correspond to properties of a class `T`, you could have a `Predicate` – fps Oct 01 '20 at 13:24
  • In your example, this should not work: pc.and(pL.test("abcd")) To use and(predicate) method, you should chain predicates like this : predicate1.and(predicate2).and(predicate3).test(myVar) But all predicates should be of the same type. – lohnns Oct 01 '20 at 13:30
  • Your code doesn't even compile. `pL.test("abcd")` returns a boolean, but `and` expects a *predicate*. (`incompatible types: boolean cannot be converted to Predicate super Integer>`). – Polygnome Oct 01 '20 at 13:32
  • That should be a hint for you, looking at the expected types and the error messages... – Polygnome Oct 01 '20 at 13:32
  • Does this answer your question? [Implement predicate chaining based on different types](https://stackoverflow.com/questions/45711123/implement-predicate-chaining-based-on-different-types) – flaxel Oct 01 '20 at 13:36

1 Answers1

2

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.

Polygnome
  • 7,639
  • 2
  • 37
  • 57