Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic bounded wildcard of function input type

While reading the Stream interface source code I found this method signature:

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

I wonder why the input type of mapper is ? super T while the output type is ? extends R, why not use ? extends for both?

like image 256
toandv Avatar asked Aug 21 '15 11:08

toandv


People also ask

What are wild cards in a generic method?

In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific).

What is a bounded generic type?

If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.

What is the difference between a wildcard bound and a type parameter bound?

What is the difference between a wildcard bound and a type parameter bound? A wildcard can have only one bound, while a type parameter can have several bounds. A wildcard can have a lower or an upper bound, while there is no such thing as a lower bound for a type parameter.

What happens when we use a bounded wildcard?

Use an upper-bounded wild card only when values are to be retrieved and processed and the data structure (ArrayList) won't be changed. This means that the corresponding argument of a call on m2 can be an ArrayList whose elements are of any class that is Integer or a superclass of Integer, including Number and Object.


2 Answers

Consider you want to map a CharSequence to another CharSequence (thus T = R = CharSequence). Which functions will work for you?

Function<Object, String> fn1 = Object::toString;

Is it good for you? Yes, because it can take any CharSequence (which is also Object) and convert it to the String (which is also CharSequence).

Function<CharSequence, StringBuilder> fn2 = StringBuilder::new;

Is it good for you? Yes, because it can take any CharSequence and convert it to the StringBuilder (which is also CharSequence).

Function<String, String> fn3 = String::trim;

Is it good for you? No, because it cannot take any CharSequence, only some of them.

Thus you can see that first type argument must be CharSequence or any superclass, but second must be CharSequence or any subclass.

like image 155
Tagir Valeev Avatar answered Sep 29 '22 23:09

Tagir Valeev


Because of PECS :) - Producer Extends, Consumer Super

Producer Extends - If you need a List to produce T values (you want to read Ts from the list), you need to declare it with ? extends T

Consumer Super - If you need a List to consume T values (you want to write Ts into the list), you need to declare it with ? super T

like image 44
Casper Avatar answered Sep 29 '22 21:09

Casper