【问题标题】:Java Streams: find if stream contains nullJava Streams:查找流是否包含null
【发布时间】:2017-06-01 18:39:04
【问题描述】:

很可能是重复的,但是我找不到任何特定的。

给定

public static void main(String[] args) {
    System.out.println(
            Arrays.asList(null, null, 1)
                    .stream()
                    .filter(obj -> obj == null)
                    .findAny()
                    .isPresent()
    );
}

期待

至少应该有效(即返回 false,因为 findAny 返回可选)。

实际

NullPointerException 被抛出

问题

这是错误还是功能?

感谢您的意见和解释。

【问题讨论】:

  • 查看我修改后的答案

标签: java java-8 java-stream


【解决方案1】:

此行为在 findAny() 的 Javadoc 中突出显示 https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#findAny--

返回:一个可选的描述这个流的一些元素,或者一个 empty 如果流为空,则可选

Throws:NullPointerException - 如果选择的元素为 null

由于您正在过滤,因此 Stream 仅包含空值,因此您将按预期获得 NullPointerException。

【讨论】:

    【解决方案2】:

    如果您将代码更改为使用anyMatch 而不是filter(...).findAny().isPresent(),它将按预期工作:

    boolean found = Arrays.asList(null, null, 1)
            .stream()
            .anyMatch(Objects::isNull);
    
    System.out.println(found); // true
    

    至于为什么您的版本因 NPE 失败,在 Stream.findAny docs 中写道:

    投掷:

    NullPointerException - if the element selected is null

    所以这是预期的行为。


    编辑: NPE 发生是因为Optional.of 用于构造findAny() 返回的值。根据文档,Optional.of 需要一个非空值:

    返回一个具有指定当前非空值的 Optional。

    无论如何,我想你想知道为什么在构建findAny() 返回的值时使用Optional.of 而不是Optional.ofNullable...

    好吧,我只能推测,但我认为findAny()findFirst() 旨在查找符合某些条件的值,即名称以A 开头的Person。您可能希望知道您的流中是否有null 元素。但是在这种情况下,您不需要实际找到这样的元素,因为您已经知道,如果找到它,它将是,嗯...只是null。因此,仅检查您的流是否包含null 就足够了,您可以完美地使用anyMatch() 来查找是否是这种情况。

    换句话说,找到null 的元素没有多大用处,因为你不能用它做任何事情(除了知道它是null)。


    编辑 2: 正如用户 @holi-java 在下面的评论中指出的那样,如果 findAny() 返回 Optional.ofNullable(null),那么将无法知道是否找到 null .在这种情况下,结果会不明确,因为Optional.ofNullable(null).equals(Optional.empty()) == true,即会导致混淆,因为Optional.ofNullable(null).isPresent() == false,意味着没有找到匹配的值。

    【讨论】:

    • 好吧,干得好。又是时差提交,^_^.
    • a Optional 有 2 个状态:absentpresent。如果 findAny 使用 Optional.ofNullable 那么它有 3 个状态:absent & null & present。如果我们想区分absentnull,那么我们必须与optional == Optional.empty()进行比较,然后我们返回检查一个对象是否为空,因为object == nullOptional失去了它的作用以避免检查@987654362 @s,并且不能将Optional 与 3 个状态进一步链接。
    • @holi-java 也许是我误解了你...我的想法如下:如果 findAny 使用 Optional.ofNullable 返回找到的值,如果找到的值为 null,那么您将无法知道是否找到该值,因为具有 null 值的 Optional 是空 Optional。
    • @holi-java 我的意思是 findAny 不需要三个状态,只需要两个:found 和 not_found。对于非常特殊的情况,当您想知道您的流是否有空元素时,请使用 anyMatch
    • @Federico Peralta Schaffner:嗯,原则上,搜索条件可以包括 null 作为可能的结果,而不是搜索exactlynull。但是,这可以被认为是一种罕见的极端情况。我从来不需要这个。除此之外,如果我想知道列表是否包含null,我会使用list.contains(null) 而不是使用流API...
    【解决方案3】:

    Here'sfindAny() 的文档,是这么写的:

    抛出:NullPointerException -

    如果选择的元素为空

    因此,如果您尝试在空对象上调用 findAny(),您将始终得到 NPE。

    您可以改用anyMatch,例如:

    Arrays.asList(null, null, 1).stream().anyMatch(e -> e == null));
    

    【讨论】:

      【解决方案4】:

      这不是错误,它是在抛出 NPE 的 Optional 实例上调用 get() 的结果。导致它的确切调用是findAny(),它给出了以下堆栈跟踪:

      Exception in thread "main" java.lang.NullPointerException
          at java.util.Objects.requireNonNull(Objects.java:203)
          at java.util.Optional.<init>(Optional.java:96)
          at java.util.Optional.of(Optional.java:108)
          at java.util.stream.FindOps$FindSink$OfRef.get(FindOps.java:193)
          at java.util.stream.FindOps$FindSink$OfRef.get(FindOps.java:190)
          at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
          at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
          at java.util.stream.ReferencePipeline.findAny(ReferencePipeline.java:469)
          at StreamTest.main(StreamTest.java:17)
      

      还有the documentation for findAny()指定可以抛出NPE:

      Throws:NullPointerException - 如果选择的元素为 null

      使用anyMatch()可以达到预期效果:

      Arrays.asList(null, null, 1).stream().anyMatch(obj -> obj == null)
      

      为什么ofNullable()没有在findAny()的实现中使用?

      API 的设计者不想假设 null 是指该值不存在(缺失值)还是存在但等于 null。此外,您仍然可以在任何流上使用map(Optional::isNullable)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-05-25
        • 2019-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-29
        相关资源
        最近更新 更多