Java 8 中的空安全集合作为流

Posted

技术标签:

【中文标题】Java 8 中的空安全集合作为流【英文标题】:Null safe Collection as Stream in Java 8 【发布时间】:2017-05-26 04:48:11 【问题描述】:

我正在寻找可以制作集合流的方法,但它是 null 安全的。如果collection 为null,则返回空流。像这样:

Utils.nullSafeStream(collection).filter(...);

我已经创建了自己的方法:

public static <T> Stream<T> nullSafeStream(Collection<T> collection) 
    if (collection == null) 
        return Stream.empty();
    
    return collection.stream();

但我很好奇,标准JDK中是否有类似的东西?

【问题讨论】:

您首先应该尽量避免使用null 集合。最佳做法是更喜欢使用空集合。 是的,我同意,但如果你依赖别人的库,你别无选择。 在这种情况下,当它返回 null 时,您可以简单地将您从该库收到的集合替换为空集合。有点像 greg 的解决方案。 【参考方案1】:

你可以使用Optional

Optional.ofNullable(collection).orElse(Collections.emptySet()).stream()...

我任意选择Collections.emptySet()作为默认值,以防collection为空。如果collection 为空,这将导致stream() 方法调用产生一个空的Stream

例子:

Collection<Integer> collection = Arrays.asList (1,2,3);
System.out.println (Optional.ofNullable(collection).orElse(Collections.emptySet()).stream().count ());
collection = null;
System.out.println (Optional.ofNullable(collection).orElse(Collections.emptySet()).stream().count ());

输出:

3
0

或者,按照 marstran 的建议,您可以使用:

Optional.ofNullable(collection).map(Collection::stream).orElse(Stream.empty ())...

【讨论】:

Optional.ofNullable(collection).map(Collection::stream).orElse(Stream.empty()); 是一个可能的等效解决方案,您不必选择Collections.emptySet() 正如@StuartMarks 提到的使用、抽象使用和滥用:Rule #4:通常为从中链接方法以获取值的唯一目的 @DidierL 我现在不能看那个 youtube 剪辑,但我的第一印象是,总的来说,我不同意。我今天晚些时候会检查一下。不过,使用collection != null ? collections.stream() : Stream.empty();,我们这里的案例看起来很干净。 @marstran Stuart Marks 的观点是,一般来说,不使用可选项会更具可读性(除了它避免了一些装箱和发件箱之外)。当然,这仍然是一个指导方针。 我认为这取决于链条。如果它是一个只检查传入引用的 null 的链,那可能是矫枉过正。但是,如果您要深入到对象图的两个或多个级别并在获取值的每一步都检查 null ,则使用 Optional 进行链接很有用。那时你正在压缩一堆嵌套的条件语句。在这一点上,恕我直言,可选链接更清晰,更易于阅读。【参考方案2】:

你可以使用 org.apache.commons.collections4.CollectionUtils::emptyIfNull 函数:

import static org.apache.commons.collections4.CollectionUtils.emptyIfNull;
      
emptyIfNull(list).stream()
                 .filter(...);

【讨论】:

我其实很喜欢这个解决方案,因为它非常简单。但是,需要外部库,但在 Maven 和 Gradle 的世界中,这不是问题。我知道我要的是 JDK8,但显然没有这么简单的东西。 不能将orElseorElseThrow 用于此,但Optional.ofNullable() 提供这两种方法。 取决于要求。但是,如果您实际上只是想在 .orElse() 调用中使用 emptyCollection,我觉得这更容易阅读。【参考方案3】:

不确定是否有帮助,但从 Java 9 开始,您可以写:

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

【讨论】:

【参考方案4】:

您的collectionAsStream() 方法可以简化为比使用Optional 时更简单的版本:

public static <T> Stream<T> collectionAsStream(Collection<T> collection) 
    return collection == null ? Stream.empty() : collection.stream();

请注意,在大多数情况下,最好在构建流管道之前仅测试空值:

if (collection != null) 
    collection.stream().filter(...)
 // else do nothing

您想要的似乎仅在您需要返回流(包括用于平面映射)或将其与另一个流连接时才有用。

【讨论】:

【参考方案5】:

如果下载库org.apache.commons.collections4 不是一个选项,您可以编写自己的包装器/方便方法。

public static <T> Stream<T> asStream(final Collection<T> collection) 
    return collection == null ? ( Stream<T> ) Collections.emptyList().stream() 
                              : collection.stream();

或者用Optional.ofNullable包装集合

public static <T> Stream<T> asStream(final Collection<T> collection) 
    return Optional.ofNullable(collection)
            .orElse( Collections.emptySet()).stream();

【讨论】:

【参考方案6】:

你可以使用类似的东西:

public static void main(String [] args) 
    List<String> someList = new ArrayList<>();
    asStream(someList).forEach(System.out::println);


public static <T> Stream<T> asStream(final Collection<T> collection) 
    return Optional.ofNullable(collection)
            .map(Collection::stream)
            .orElseGet(Stream::empty);

【讨论】:

使用.orElseGet(Stream::empty) 懒惰地评估替代方案会更好。 是的,没错 :) 我无法编辑它,因为这是一个很小的变化,但对于其他任何觉得这很有用的人来说——“Stream.empty()”对我不起作用。但 Stream::empty 就像 Nicolas 建议的那样。 谢谢你——这对学习很有帮助,所以我也想做我的一小部分。 这是不使用任何第三方库的最佳答案。

以上是关于Java 8 中的空安全集合作为流的主要内容,如果未能解决你的问题,请参考以下文章

简洁方便的集合处理——Java 8 stream流

Java 8新特性之Stream流

处理 JPA 中的空或 null 集合参数

Java 8 Streams 可以对集合中的项目进行操作,然后将其删除吗?

Java并发:并发集合ConcurrentHashMap的源码分析

《Java 8 实战》---- 流