Skip to content

Using wildcards in stream terminal operations


I’am reading a Java book and got to the chapter about StreamAPI classes. So, my questions is: why in terminal operation methods using lower bounded wildcards, like:

void forEach(Consumer<? super T> consumer)
boolean anyMatch(Predicate <? super T> pred)
Optional<T> min(<? super T> comparator)

Indeed, in fact, you can use unbounded wildcards like this:

void forEach(Consumer<?> consumer)
boolean anyMatch(Predicate <?> pred)
Optional<T> min(<?> comparator)

Is there any reason to use exactly lower- bounded wildcards?


You cannot use unbounded wildcards for these methods.

Suppose you are implementing your own forEach method. If it accepts a Consumer<? super T>, you can pass a T to it, because you know that T is a subtype of whatever the Consumer‘s parameter’s type is and can therefore safely make the consumer accept an element of type T.

However, if it accepts a Consumer<?>, you can’t directly pass a T to it without casting. There is no guarantee that the consumer accepts Ts and not some other type? Furthermore, as Louis Wasserman pointed out in his answer, you would be able to pass a Consumer<Long> to the forEach method of a Stream<String>.

Lower-bounded wildcards are as loose as you can get while also being typesafe. With just plain Consumer<T> and Supplier<T> parameters, you wouldn’t be able to directly pass a Consumer<Object> to a Stream<String>‘s forEach method without casting. With unbounded wildcards, you would be able to pass basically anything, which defeats the whole point of using generics.