代码之家  ›  专栏  ›  技术社区  ›  checketts

从可空对象创建流的惯用方法

  •  45
  • checketts  · 技术社区  · 10 年前

    什么是 最好的/惯用的 执行 空值检查 在生成流之前?

    我有一个方法可以接收 List 那可能是 null 所以我不能打电话 stream() 在传递的值上。如果值为空,是否有一些静态助手会给我一个空流?

    7 回复  |  直到 2 年前
        1
  •  79
  •   gdejohn    6 年前

    我同意 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.<T>ofNullable(T) ,返回给定 null 参数,否则将该参数作为其唯一元素的流。如果参数是集合,则可以 flatMap 把它变成一条小溪。

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

    这并没有像Stuart Marks所讨论的那样滥用Optional API,而且与三元运算符解决方案不同,没有出现空指针异常的机会(例如,如果你不注意并打乱了操作数的顺序)。它还可以使用上限通配符,而不需要 SuppressWarnings("unchecked") 感谢您的签名 平面地图 ,这样你就可以得到 Stream<T> 任何子类型的元素集合 T .

        2
  •  27
  •   checketts    10 年前

    我能想到的最好的办法就是使用 Optional 使用 orElseGet 方法

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

    已更新 使用@Misha的建议 Collections::emptyList 结束 ArrayList::new

        3
  •  18
  •   Community CDub    8 年前

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

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

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

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

    如果我是为real(也就是说,为一个真正的库,而不仅仅是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<? extends T> Stream<T> 这是安全的,但编译器不知道。)

        4
  •  12
  •   piotrek    8 年前

    apache通用集合4:

    CollectionUtils.emptyIfNull(list).stream()
    
        5
  •  8
  •   Michal Foksa    4 年前

    Java 8:

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

    Java 9:

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

    Apache Commons集合4:

    import org.apache.commons.collections4.CollectionUtils;
    
    CollectionUtils.emptyIfNull(collection)
        .stream()
    
        6
  •  0
  •   JustifiedAndAncient    8 年前

    就我个人而言,我认为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);
    }
    
        7
  •  0
  •   Alexander Ivanchenko    2 年前

    Java 16

    这里有一个生成流的选项 可为空的源 使用Java 16 Stream.mapMulti() .

    此操作需要类型为的参数 BiConsumer 即消费者 两个论点 :a 流元素 和一个 消费者 结果类型的。提供给消费者的每个值都将成为一个新的流元素,取代初始元素。

    public <T> Stream<T> getStream(Collection<? extends T> c) {
    
        return Stream.ofNullable(c).mapMulti(Iterable::forEach);
    }
    

    其中 方法参考 Iterable::forEach 代表 双消费者 是以下lambda表达式的等价项(为描述性提供的显式类型):

    (Collection<? extends T> coll, Consumer<T> consumer) -> coll.forEach(consumer)
    

    以及 flatMap() 活动 mapMulti() 旨在执行 一对多 转换 将消耗的原始流元素替换为 0+ ( 零或更多 )元素。

    笔记 那个 mapMulti() 会比 flatMap() 如果您需要展平大量仅包含少数元素或可以为空的列表。以下是 API Note :

    这种方法是 更可取 flatMap 在以下情况下:

    • 小的 ( 可能为零 )元素数量。使用此方法 避免了开销 属于 创建 Stream 根据需要,为每组结果元素创建实例 通过 平面地图 . ...

    笔记

    1. 列表( 以及其他集合和阵列 )是数据的容器,即当你需要一个你感兴趣的列表中的东西时,实际值存储在里面。一个可为空的数据容器迫使您采取与业务逻辑无关的正确防御措施,您或同事可能会忘记这一点(这会产生一个随时可能出现的问题)。

    无论可为null的集合的来源如何,如果您有可能更改正在使用的代码,则可以消除实际问题,而不是使用 Stream.ofNullable() 或虐待 Optional .

    以下是可为空集合的可能来源及其处理方法:

    • 可为null的集合来自包装在其周围的自定义对象 空集合 默认情况下。
    • 例如,数据是作为JSON负载接收的,并且表示集合的属性缺失或为空。这基本上是前一个伪装的案例。检查分析工具的功能,很可能会找到一种方法来为不存在的属性分配默认值。
    • 如果有一个方法返回可为null的Collection,则在返回值之前添加一个条件,而不是 空支票 空友好型 代码中到处都是动作。参考经典书籍 “有效的Java” Joshua Bloch,Item:“返回空集合或数组,而不是空值”。

    2. 如果您需要一种快速的方法使代码工作,但您希望知道传入的列表 null ,然后添加条件语句以在日志中反映事件:

    if (list != null) logger.log( ... );
    

    3. 最后,作为 @斯图尔特·马克斯 已在中指出 his answer to this question 可选择的 不是为之设计的 执行/隐藏 空检查。以下是关于此主题的更多参考: