【问题标题】:Filter nullable values from stream and updating nullable property从流中过滤可空值并更新可空属性
【发布时间】:2016-11-22 06:47:25
【问题描述】:

如果我有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 值)

【问题讨论】:

  • str.filter(Objects::nonNull).map(Objects::requireNonNull)

标签: java java-stream


【解决方案1】:

好吧,所有基于 OptionalObjects 的解决方案都假定检查器知道其方法的语义,因为它们没有显式注释。

由于filter 从不更改类型,因此需要检查器的深入支持才能将其建模为Stream&lt;@Nullable X&gt;Stream&lt;@NonNull X&gt; 转换,即使它理解过滤器函数的语义。

更简单的方法是使用map,因为它允许更改元素类型:

Stream<@NonNull Object> s = str.filter(Objects::nonNull).map(Objects::requireNonNull);

这里,过滤操作确保没有null元素,但不会改变正式的元素类型。相比之下,map 操作允许更改形式类型,并且函数 Objects::requireNonNull 将可空输入转换为非空输出,假设审计工具知道这一点,如前所述,这些 JRE 提供的方法没有注释。

由于requireNonNull 会为null 值抛出异常,因此只有filtermap 的组合允许删除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 下运行。

【讨论】:

  • 我怀疑有更好的答案,所以我会接受你的答案。谢谢!
猜你喜欢
  • 1970-01-01
  • 2016-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多