如果我有Stream<@Nullable Object>
,我可以过滤掉这样的空元素:
Stream<@Nullable Object> s = str.filter(Objects::nonNull);
然而,这会返回一个可以为空的对象流。是否有一种优雅的方式来返回NonNull流元素?在这个地方,我已经知道元素不能为空。
这就是我想出的,但它太长了,imo:
Stream<@NonNull Object> s = str.map(Optional::ofNullable).filter(Optional::isPresent).map(Optional::get)
(这意味着Optional :: get将始终返回NonNull值)
答案 0 :(得分:2)
好吧,基于Optional
或Objects
的所有解决方案都假设检查器知道其方法的语义,因为它们没有明确的注释。
由于filter
永远不会更改类型,因此需要检查程序的深度支持才能将其建模为Stream<@Nullable X>
→Stream<@NonNull X>
转换,即使它理解了过滤器函数的语义
更简单的方法是使用map
,因为它允许更改元素类型:
Stream<@NonNull Object> s = str.filter(Objects::nonNull).map(Objects::requireNonNull);
这里,过滤操作确保没有null
个元素,但不会更改形式元素类型。相反,map
操作允许更改正式类型,函数Objects::requireNonNull
将可空输入转换为非空输出,假设审计工具知道这一点,如上所述,这些JRE提供的方法具有没有注释。
由于requireNonNull
会为null
值引发异常,因此只有filter
和map
的组合才能实现删除null
值和更改所需的行为形式元素类型。
如果审计工具不理解JRE方法的语义,您必须自己创建一个等效方法,然后使用注释,
class MyObjUtil {
public static <T> @NonNull T requireNonNull(@Nullable T obj) {
if(obj==null) throw new NullPointerException();
return obj;
}
}
应由任何合理的检查员识别为正确,并将其用作
Stream<@NonNull Object> s = str.filter(Objects::nonNull).map(MyObjUtil::requireNonNull);
使用Java 9可以简化基于Optional
的方法:
Stream<@NonNull Object> s = str.flatMap(o -> Optional.ofNullable(o).stream());
可以进一步简化:
Stream<@NonNull Object> s = str.flatMap(o -> Stream.ofNullable(o));
但当然,这又需要一个工具来理解这些方法。或者你重新实现逻辑:
class MyStreamUtil {
public static <T> Stream<@NonNull T> ofNullable(@Nullable T obj) {
return obj==null? Stream.empty(): Stream.of(obj);
}
}
Stream<@NonNull Object> s = str.flatMap(o -> MyStreamUtil.ofNullable(o));
然后在Java 8下工作。