Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wildcard generics of map() method

This is the implementation of map() method:

public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent()) {
        return empty();
    } else {
        return Optional.ofNullable(mapper.apply(value));
    }
}

When I call map() like this, what is the type of T and U? What is the type of wildcard (?)? It is very confusing.

Optional<String> os1 = Optional.of("Optional String");
Optional<String> os2 = os1.map(s -> s.toUpperCase());

Javadoc statement says:

@param <U> is the type of the value returned from the mapping function.

Does "mapping function" mean map() method or argument of the map()?

like image 564
EnDelt64 Avatar asked Dec 05 '18 16:12

EnDelt64


3 Answers

Regardless if it's Stream or Optional, the purpose of the method map which accepts Function<? super T, ? extends U> is to map each input value T to an output of the same or different type U. The wildcard is used for extending the range of mapping possibilities.

Does "mapping function" mean map() method or argument of the map()?

The "mapping function" is a T -> U mapping implementation of an anonymous class of the Function interface which might be shortened with a lambda expression or a method reference.

In your sample, the T and U are both String since you map the String to its upper-case variation which is a String again. It behaves the same like UnaryOperator<T> a special case of Function<T, T> which consumes and returns the same type.

On the other hand, if you map:

os1.map(s -> s.length())
  • The T is String
  • The U is Integer since the method String::length produces an integer

You might shorten the lambda with a method reference:

Optional<String> os2 = os1.map(String::toUpperCase);

... or better use both of the Optionals together:

Optional<String> os1 = Optional.of("Optional String");
                               .map(String::toUpperCase);
like image 105
Nikolas Charalambidis Avatar answered Oct 22 '22 02:10

Nikolas Charalambidis


Firstly, just to answer your question of:

Does "mapping function" mean map() method or argument of the map()?

This "mapping function" refers to the argument supplied to the map method of the Optional<T> type.

To make things easier to understand, just forget about the wildcard (?) for a moment as we could do without its confusion and focus on the type T and U, the simplified version below:

public <U> Optional<U> map(Function<T, U> mapper) { ... }
  • Where T represents any type of object as input and U represents any type as output.
  • Function<T, U> mapper represents a function taking an object of type T and returns a value of type U
  • Optional<U> is an Optional encapsulating an object of type U.

You could visualize the mapper function as:

         _ _ _ _ _ _ _ _ _ 
        |                 |
        |                 |
T ----->|      logic      | -----> U
        |                 |
        |_ _ _ _ _ _ _ _ _|

So, given the above visualisation and your example of:

Optional<String> os1 = Optional.of("Optional String");
Optional<String> os2 = os1.map(s -> s.toUpperCase());

The function passed to the map method of the Optional type (s -> s.toUpperCase() ) is Function<String, String> mapper i.e. T in the visualization above becomes String and U in the visualization above becomes String i.e.

             _ _ _ _ _ _ _ _ _ 
            |                 |
            |                 |
  String -->|      logic      | ---> String
            |                 |
            |_ _ _ _ _ _ _ _ _|

So, when the above function is invoked by the map method of the Optional type, it will perform some operation represented by the "logic" above in the visualization, in this specific case the logic is simply converting the input string to an uppercase string.

Once that is done, the map method of the Optional<T> type wraps that uppercase string into an Optional object hence it returns an Optional<String>.

like image 23
Ousmane D. Avatar answered Oct 22 '22 03:10

Ousmane D.


Seems to me you have a wrong src (with Javadoc) project of you JDK. Consider what the Oracle Docs about Optional in Java 8 says:

map(Function mapper)

If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result.

like image 23
Leandro Lima Avatar answered Oct 22 '22 01:10

Leandro Lima