and()
and or()
methods of Predicate interface in Java 8 takes any super type of T
, that is ? super T
and not ? extends T
. I was expecting it to take any type that extends T
. The motivation for me to think this way is, since T
is the type I'm defining my predicate on, the compound predicate also should be on T
(that is any subtype of T
). What is the reason behind that being ? super T
. Can someone help me understand?

- 285,553
- 42
- 434
- 765

- 307
- 2
- 13
-
1See [“What is PECS (Producer Extends Consumer Super)?”](http://stackoverflow.com/q/2723397/2711488) – Holger Mar 14 '17 at 11:19
1 Answers
So here is my understanding of it. Suppose we have this:
interface MyPredicate<T> {
boolean test(T t);
}
And these declarations:
MyPredicate<? extends Number> p1 = (Number n) -> n.intValue() > 9;
MyPredicate<Integer> p3 = null;
MyPredicate<Long> p4 = null;
Because Integer
and Long
are sub-types of Number
, we can do this:
p1 = p3;
p1 = p4;
At the same time, let's suppose p3
and p4
are not null. The only types they can accept in test would be Integer
and Long
.
p3.test(12);
p4.test(12L);
But what would p1
accept? Integer
, but what if it points to MyPredicate<Long>
? Long
, but what if it points to MyPredicate<Integer>
?
So there is no way to apply p1 to anything but null
in this case.
Let's introduce p2
:
MyPredicate<? super Number> p2 = (Number n) -> n.intValue() > 10;
Since it uses super
we can't even do this:
p2 = p3; // will not compile
p2 = p4; // will not compile
But this time we know that we will have some type that will have Number
as it's super type, so we can safely apply Number here. Meaning :
p2.test(12); // 12 is Number
will compile just fine; since we are 100% sure that whatever the type, it is a super type of Number.
Let's change MyPredicate
:
interface MyPredicate<T> {
boolean test(T t);
default MyPredicate<T> and(MyPredicate<? extends T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t); // this will not compile
}
}
Because we have used extends
, we don't know the actual type, so it will fail, unlike super
:
interface MyPredicate<T> {
boolean test(T t);
default MyPredicate<T> and(MyPredicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t); // compiles just file
}
}

- 117,005
- 15
- 201
- 306
-
Eugene, now I understand why using extends will not be helpful. One small correction to your explanation. `? super Number` can take any type that is a super type of Number. In the above explanation you mentioned it will be guaranteed to extend Number which is not true. – chandra_cst Mar 17 '17 at 22:52