java 8可选map()使用函数引用抛出NPE,但不使用完整的lambda语法

mat*_*eus 5 java lambda intellij-idea java-8

这是一个错误还是一个功能?

NPE下面失败了

Function<String, String> f = null;
Optional.<String>empty().map(f).orElse(null);
Run Code Online (Sandbox Code Playgroud)

但不是

Function<String, String> f = null;
Optional.<String>empty().map(value -> f.apply(value)).orElse(null);
Run Code Online (Sandbox Code Playgroud)

例如,IntelliJ建议用第二个表达式替换第二个表达式作为等价物,这对我来说是有意义的,直到现在.

这种行为的原因是执行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));
    }
}
Run Code Online (Sandbox Code Playgroud)

相反,如果map()实施时:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

我们会在前两个片段之间获得一致的行为.任何理由map()不是第二次实施?

Tun*_*aki 8

这不是一个错误,因为它是明确记录的.引用Optional.map(mapper)Javadoc:

如果存在值,则将提供的映射函数应用于它[...]
...

抛出:

NullPointerException - 如果映射函数是 null

因此,无论是否存在值,该map方法总是抛出一个NullPointerException,如果mapper给定的是null:这解释了第一种情况下的异常.但是,仅当存在值时才应用映射器:这解释了为什么在第二种情况下没有例外.

  • 通常,我们会尽早验证方法参数(快速失败,促进故障原子性等).这通常扩展到检查可能最终未被使用的参数.(当然,在与JDK一样多的时间,代码和开发人员的代码库中,像这样的一般原则不可能以完美的一致性实现.) (4认同)
  • 实际上,[`orElseGet`](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#orElseGet-java.util.function.Supplier-)的工作原理真的很奇怪不同的方式:仅当供应商为空*并且*值不存在时,它才会抛出NPE.Paul Sandoz [同意](http://mail.openjdk.java.net/pipermail/core-libs-dev/2015-September/035426.html)错误地以这种方式完成了"orElseGet"规范. (3认同)