【问题标题】:How to best create a Java 8 stream from a nullable object?如何最好地从可为空的对象创建 Java 8 流?
【发布时间】:2023-03-17 23:14:01
【问题描述】:

在获取流之前进行空值检查的最佳/惯用方法是什么?

我的方法正在接收可能为空的List。所以我不能只在传入的值上调用.stream()。如果值为空,是否有一些静态助手会给我一个空流?

【问题讨论】:

  • 我强烈建议在列表提供方工作。选项的全部目的是不处理 null 引用。如果一个方法返回一个可能是null 的列表,它应该返回一个可选的。如果那不可能,您可以将其包装成一个可选的(根据答案)。另外,您想对该列表做一些事情,即如果它存在,您想使用它。所以只需拨打Optional.ifPresent就可以了。

标签: java java-8 java-stream


【解决方案1】:

我同意 Stuart Marks 的观点,即 list == null ? Stream.empty() : list.stream() 是执行此操作的正确方法(请参阅 his answer),或者至少是在 Java 9 之前执行此操作的正确方法(请参见下面的编辑),但我会留下这个答案来演示 Optional API 的用法。

<T> Stream<T> getStream(List<T> list) {
    return Optional.ofNullable(list).map(List::stream).orElseGet(Stream::empty);
}

编辑: Java 9 添加了静态工厂方法Stream.&lt;T&gt;ofNullable(T),它返回给定null 参数的空流,否则返回以参数为唯一元素的流。如果参数是一个集合,那么我们可以flatMap 将它变成一个流。

<T> Stream<T> fromNullableCollection(Collection<? extends T> collection) {
    return Stream.ofNullable(collection).flatMap(Collection::stream);
}

这不会滥用 Stuart Marks 所讨论的 Optional API,并且与三元运算符解决方案相比,没有机会出现空指针异常(例如,如果您没有注意并搞砸了操作数)。由于flatMap 的签名,它还可以使用上限通配符而不需要SuppressWarnings("unchecked"),因此您可以从T 的任何子类型的元素集合中获得Stream&lt;T&gt;

【讨论】:

  • 我喜欢这个帮助器示例,我可以重复使用一堆并避免在我的代码中乱扔Optional.orNullable
  • List::stream中不需要显式类型参数&lt;T&gt;;它没有。并且.orElse(Stream.empty()) 可以替换为.orElseGet(Stream::empty),因为它避免构造空流,所以效率稍高。
  • @Holger,我做了这些更改,但我想知道Stream::empty 在幕后实际产生了什么。匿名类?
  • “How will Java lambda functions be compiled?”“Does a lambda expression create an object on the heap every time it's executed?”。实际上,会有一个匿名类的实例,但在每次执行代码时都会是同一个实例(而Stream.empty() 每次都会返回一个新实例)。
【解决方案2】:

我能想到的最好的办法是将OptionalorElseGet 方法结合使用。

return Optional.ofNullable(userList)
                .orElseGet(Collections::emptyList)
                .stream()
                .map(user -> user.getName())
                .collect(toList());

更新 @Misha 建议使用 Collections::emptyList 而不是 ArrayList::new

【讨论】:

  • 最好使用Collections::emptyList 而不是ArrayList::new。它使意图更清晰,并且(稍微)更有效率。
【解决方案3】:

在其他答案中,Optional 实例是在同一语句中严格创建和使用的。 Optional 类主要用于communicating with the caller 关于是否存在返回值,如果存在则与实际值融合。完全在一个方法中使用它似乎没有必要。

让我提出以下更平淡的技巧:

static <T> Stream<T> nullableListToStream(List<T> list) {
    return list == null ? Stream.empty() : list.stream();
}

我想现在三元运算符有点过时了,但我认为这是最简单和最有效的解决方案。

如果我是真的写这个(也就是说,对于一个真正的库,而不仅仅是 Stack Overflow 上的示例代码),我会放入通配符,以便流返回类型可以与 List 类型不同。哦,它可以是一个集合,因为这是定义 stream() 方法的地方:

@SuppressWarnings("unchecked")
static <T> Stream<T> nullableCollectionToStream(Collection<? extends T> coll) {
    return coll == null ? Stream.empty() : (Stream<T>)coll.stream();
}

(警告抑制是必要的,因为从Stream&lt;? extends T&gt; 转换为Stream&lt;T&gt; 是安全的,但编译器不知道。)

【讨论】:

    【解决方案4】:

    apache commons-collections4:

    CollectionUtils.emptyIfNull(list).stream()
    

    【讨论】:

    • 嗨,piotrek;您的代码可能是正确的,但在某些情况下会更好;例如,您可以解释这个提议的更改如何以及为什么会解决提问者的问题,可能包括指向相关文档的链接。这将使它对他们更有用,对正在寻找类似问题的解决方案的其他网站读者也更有用。
    • 不确定应该解释什么。 apache commons-collections 是最标准的 java 库之一。它如何解决OP问题?它直接执行 OP 需要的操作 - 它从可空列表生成流
    【解决方案5】:

    Java 8:

    Optional.ofNullable(list)
       .orElseGet(Collections::emptyList)
       .stream()
    

    Java 9:

    Stream.ofNullable(collection)
        .flatMap(Collection::stream)
    

    Apache Commons Collections 4:

    import org.apache.commons.collections4.CollectionUtils;
    
    CollectionUtils.emptyIfNull(collection)
        .stream()
    

    【讨论】:

      【解决方案6】:

      我个人认为不推荐使用 null 并尽可能使用 Optional 尽管有(很小的)性能开销。所以我使用来自 Stuart Marks 的接口和基于 gdejohn 的实现,即

      @SuppressWarnings("unchecked")
      static <T> Stream<T> nullableCollectionToStream(Collection<? extends T> coll)
      {
          return (Stream<T>) Optional.ofNullable(coll)
                                 .map(Collection::stream)
                                 .orElseGet(Stream::empty);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-31
        • 1970-01-01
        相关资源
        最近更新 更多