Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java 8 Optional map() throw NPE with function reference but not with full lambda syntax

Is this a bug or a feature?

Below fails with NPE

Function<String, String> f = null;
Optional.<String>empty().map(f).orElse(null);

But not

Function<String, String> f = null;
Optional.<String>empty().map(value -> f.apply(value)).orElse(null);

IntelliJ for example would suggest to replace the second expression by the first one as equivalent, which made sense to me, until now.

The reason for this behavior is the implementation of Optional#map():

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

Instead, if map() was implemented with:

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

we would get a consistent behavior between the first 2 snippets. Any reason why map() is not the second implementation?

like image 924
matthieus Avatar asked Jan 21 '16 15:01

matthieus


1 Answers

This is not a bug because it is explicitely documented. Quoting Optional.map(mapper) Javadoc:

If a value is present, apply the provided mapping function to it [...]
...

Throws:

NullPointerException - if the mapping function is null

So the map method always throw a NullPointerException, regardless of the presence of a value or not, if the mapper given is null: this explains the exception in the first case. However, the mapper is only applied if there is a value: this explains why there is no exception in the second case.

like image 169
Tunaki Avatar answered Nov 02 '22 02:11

Tunaki