Java 8 Optional.ifPresent 是我的代码错了还是eclipse?

Java 8 Optional.ifPresent is my code wrong or is it eclipse?

我是 Java 8 的新手,正在尝试 Null 类型注释和 Optional。

对于我下面的示例,我使用了 String 而不是我的 class 并且我调用 toUpperCase 只是为了调用一些东西,在我的例子中我实际上调用了一个传递参数的函数(所以不要认为我可以使用 :: operator and/or maps).

在 Eclipse 中,我打开了 Java - 编译器 - Errors/Warnings - 空分析错误。

我的测试代码如下:

public void test1(@Nullable String s) {
    // the 2nd s2 has a Potential null pointer access error. 
    // I was hoping ifPresent would imply NonNull
    Optional.ofNullable(s).ifPresent(s2 -> s2.toUpperCase());
}

@Nullable 
public String getSomeString() {
    return null;
}

public void test2() {
    String s = getSomeString();

    // This is fine, unlike the first example, I would have assumed that
    // it would know s was still nullable and behave the same way.
    Optional.ofNullable(s).ifPresent(s2 -> s2.toUpperCase());
}

似乎使用 Eclipse 类型空注释和 Optional.ifPresent 不能很好地结合在一起。

我是在浪费时间尝试让这样的东西工作吗?我是否应该恢复为将 getter 分配给临时变量然后检查是否为 null,如果不是则调用我的函数?

首先:@Nullable 接缝不属于 public Java 8 SDK。查看您导入的包:com.sun.istack.internal.Nullable.

其次:我有 运行 你的两种方法:test1(null)test2() 并且没有发生任何异常情况。一切都很好(正如预期的那样)。那么你观察到了什么?

运行 test1(null) => 没有执行 lambda 表达式。

运行 test2() => 没有执行 lambda 表达式。

我按照以下方式更改了您的测试代码:

public void test1(@Nullable String s) {
    Optional.ofNullable(s).ifPresent(s2 -> System.out.println("executed"));
}

public void test2() {
    String s = getSomeString();
    Optional.ofNullable(s).ifPresent(s2 -> System.out.println("executed"));
}

JDT 的 null 分析无法了解 JRE 和其他库中每个方法的语义。因此,看到对 ifPresent 的调用没有得出任何结论。这可以通过向 Optional 添加外部注释来补救,以便分析将方法 ofNullable 视为

<T> Optional<@NonNull T> ofNullable(@Nullable T value)

从 2015 年 6 月 24 日发布的 Eclipse Mars 开始支持外部注释。参见 Help: Using external null annotations

问题中两个变体之间的差异是由于 null 分析如何与 Java8 类型推断相结合:在变体 (1) 中,s 具有类型 @Nullable String。当在类型推断期间使用此类型时,得出的结论是 ifPresent 的参数也可以为空。在变体 (2) 中,s 具有类型 String(尽管流分析可以看到它在 getSomeString 初始化后可能为 null)。未注释的类型 String 不够强大,无法帮助类型推断得出与变体 (1) 相同的结论(尽管这可能会在 JDT 的未来版本中得到改进)。