I was going through the Predicate class introduced in java 8 which is functional interface. There is a method and inside the Predicate class which is as following for composing multiple predicates into one.
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
I have read the concept of PECS in java but still couldn't understand why in the case of Predicate we are using ? super T. How have the java programmers decided that it would be a consumer and not a producer.
I mean why lines with compile errors should not be allowed:
public class PredicateExample {
public static void main(String[] args) {
Predicate<Number> pred = n -> n.intValue() > 2;
Predicate<Integer> predInt = n -> n > 3;
//Compile error
//pred.and(predInt);
Predicate<Object> predObj = o -> Integer.parseInt(o.toString()) > 4;
pred.and(predObj); //Valid statement
Number n = new Integer(100);
System.out.println(pred.and(predObj).test(10));
System.out.println(predInt.and(pred).test(10));
//Compile error
//System.out.println(pred.and(predInt).test(10));
}
}
Predicate<T>s take in aTand give you aboolean. Yes, it is a producer ofbooleans, but that's not really relevant here. When applying PECS on a type parameter, you should think about whether the type is a producer or consumer of that type parameter.Since
Predicate<T>accepts aT, it's a consumer ofT, so it should be? superfor theTparameter.Another example:
BiFunction<T, U, V>accepts aTand aU, and produces aV, so it's a consumer ofT, consumer ofU, and producer ofV. Therefore,? superforTandU,? extendsforV. As you can see, only the type parameters matter. Anything else that the type might do, doesn't.The lines will be allowed if you flip the two sides -
predInt.and(pred), which creates aPredicate<Integer>.This is because
andis declared to produce the same type of predicate as the one it is called on, sopred.and(...)can only produce aPredicate<Number>, but aPredicate<Number>doesn't make sense here - the other conjunct can only accept integers!You can totally make it work in both orders. If you declare
andas a static method:Then you can do both of these:
But it's less readable this way :(