9

I was looking at the stream interface and found this method :

 <R> Stream<R> map(Function<? super T, ? extends R> mapper);

I can't find any reason why "? extends R" instead of R :

 <R> Stream<R> map(Function<? super T, R> mapper);

so what will be the difference if I make it like above ? isn't the "?" is the R variable that I pass ? and it will extend R I can't find a reason for it.

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Mohammad Karmi
  • 1,403
  • 3
  • 26
  • 42

3 Answers3

14

It uses ? extends R to allow functions taken by map to be declared as returning a subtype of R

For example, given this stream:

Stream<Number> numberStream = Stream.of(1, 2L);

In the following map call, R is Number, but the function is of type Function<Number, Integer>:

Function<Number, Integer> function = n -> Integer.valueOf(n.intValue());
Stream<Number> numberStream2 = numberStream.map(function); //would have failed

If it did not take ? extends R, then function would have been an invalid argument (Function<Number, Number> would have been required)

ernest_k
  • 44,416
  • 5
  • 53
  • 99
  • @earnest_k `R` here is anything that the integer extends right ? it's not only number. just to be a generic answer as "? extends R". Thanks for the answer – Mohammad Karmi Dec 13 '18 at 07:16
  • @MohammadKarmi There are two `R` in this answer. For `Function`, `R` is `Integer`. For `numberStream.map(function)`, `R` is `Number`. – ernest_k Dec 13 '18 at 07:19
  • correct. but I can use anything that the integer extend : `Stream numberStream2 = numberStream.map(function);` so R can be anything the integer extend here. that's what I wanted to say. in your example it's number Thanks :) – Mohammad Karmi Dec 13 '18 at 07:20
  • No. It has to be `Number` or a subtype of `Number`. So you can't use, for example, `Function` (`Integer` extends `Object`, but that would be invalid because `Object` is not a subtype of `Number`). If you mean *anything that extends `Integer`*, then yes - but `Integer` is a bad example because there's no subtype we could use to illustrate it :-) – ernest_k Dec 13 '18 at 07:25
  • No what I meant is that , R is the super of the Integer here. that's why this work : `Stream numberStream2 = numberStream.map(function);` R here is serliazable , please correct me if I'm wrong – Mohammad Karmi Dec 13 '18 at 07:31
  • That's correct. `R` is `Serializable` in that case, just as `R` was `Number` in my example. – ernest_k Dec 13 '18 at 07:37
  • Why is super T> in such a place? – Kuan-Yu Lin Jan 21 '22 at 07:07
2

? extends R means you can pass an object whose class is derived by R, a.k.a subclass of R.

So the map function can produce R and R's subclass as result. That is reasonable.

For example, If we have these classes: Animal, Groose (extends Animal), Egg Function<Egg, Groose> hatching

You can write this code:

List<Egg> eggs = getEggs();
List<Animal> myPets = eggs.stream().map(hatching)....

You can see that your map function requires Animal type (R), but your mapper returns Groose type (which is ? extends R). If the map function writes as <R> Stream<R> map(Function<? super T, R> mapper);, you have to add another conversion from Groose to Animal.

You can refer to this answer and understand <? extends T>.

Laohyx
  • 303
  • 3
  • 9
0

In Java Generics are invariant which means that even if S extends P the following code will throw the compile error -

List<S> list1 = neww ArrayList<>();
List<P> list2 = list1 ; // compile error

But if you have Listthen you can do the following:

List<S> list1 = neww ArrayList<>();
List<? extends P> list2 = list1 ;
Yug Singh
  • 3,112
  • 5
  • 27
  • 52