6

Why does map take its input as a Function of type <? super P_OUT, ? extends R> instead of <P_OUT, ? extends R>?

When I do for example,

List<Integer> list = new ArrayList<>();
list.stream().map(xyz -> {}); // Here xyz is always of type Integer for this instance. 
                              // Then why does it take input as "? super Integer"?

Is it because of not restricting method references? Is that the only use case?

Boann
  • 48,794
  • 16
  • 117
  • 146
  • 1
    Because it grantees right parameter and also increase range of parameters when you are using lower bound `? super P_OUT` so here you can use `P_OUT` and all superclass of `P_OUT` – Hadi J Jun 09 '19 at 10:26
  • 1
    A `Function` is given input (consumes) and returns a result (produces). Using wildcards allows flexibility in the API regarding the implementation of `Function` you pass to `map`. For instance, it being `Function super Integer, ? extends R>` lets you pass an implementation of `Function`. – Slaw Jun 09 '19 at 10:45
  • 1
    Slaw, I get it. So, it is to avoid the restriction right? In case the '? super Integer' is not there, I could not use method reference to use a function of type . Hence to overcome the restriction, they have provided "? super Integer". Is my understanding correct? – Manikandan Kbk DIP Jun 09 '19 at 10:52
  • Pretty much. Oleksandr's answer below gives examples. The duplicate has answers that give some decent explanations about covariance, invariance, and contravariance. – Slaw Jun 09 '19 at 11:58

1 Answers1

8

The wildcard <? super T> allows you to work with a broader set of types.

Suppose you have some generic function:

Function<Number, String> func = String::valueOf;

Then you could do the following:

List<Integer> list = List.of(1, 2);
Stream<String> stream = list.stream().map(func);

or the following:

List<Long> list = List.of(1L, 2L);
Stream<String> stream = list.stream().map(func);

And this is possible because the parameter to the Stream.map(...) is:

Function<? super T, ? extends R> mapper;

Which means that if, for example, T is of type Long1, then <? super Long> will allow the function to accept elements of type Long, and the following assignment will also become valid:

Function<? super Long, ? extends String> mapper = func;

With the Function<T, ? extends R> both examples above wouldn't even compile.


1 - We construct the Stream<Long> from the elements of the List<Long>.

Oleksandr Pyrohov
  • 14,685
  • 6
  • 61
  • 90