我是Java 8的新手,正在尝试Null类型注释和可选。
对于下面的示例,我使用了 String 而不是我的类,并且调用 toUpper Case 只是为了调用某些东西,在我的情况下,我实际上调用了一个传入参数的函数(所以不要认为我可以使用 :: 运算符和/或地图)。
在 Eclipse 中,我打开了 Java - 编译器 - 错误/警告 - 空分析错误。
我的测试代码如下:
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,如果不调用我的函数?
JDT 的空分析无法了解 JRE 和其他库中每个方法的语义。因此,通过看到ifPresent
的呼吁不会得出任何结论。这可以通过在Optional
中添加外部注释来补救,以便分析将方法ofNullable
视为
<T> Optional<@NonNull T> ofNullable(@Nullable T value)
从 2015 年 6 月 24 日发布的 Eclipse Mars(Eclipse Mars)开始,支持外部注释。请参阅帮助:使用外部空注释。
问题中两个变体之间的差异是由于空分析如何与 Java 8 类型推理集成:在变体 (1) 中,s
具有类型 @Nullable String
。在类型推断期间使用此类型时,可以得出结论,ifPresent
参数也是可为空的。在变体 (2) 中,s
具有类型 String
(尽管流分析可以看到在从 getSomeString
初始化后可能为 null)。未注释的类型String
不足以帮助类型推断得出与变体 (1) 相同的结论(尽管这可能会在 JDT 的未来版本中得到改进)。
首先:@Nullable
接缝不是公共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"));
}