Java Streams:查找stream是否包含null

时间:2017-06-01 18:39:05

标签: java java-8 java-stream

最有可能是重复,但我无法找到任何特定的。

鉴于

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

期望

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

实际

NullPointerException被抛出

问题

是错误还是功能?

感谢您的意见和解释。

4 个答案:

答案 0 :(得分:10)

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

  

返回:描述此流的某个元素的可选项,或者   empty如果流为空,则为可选

     

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

由于您正在进行过滤,因此Stream只包含空值,因此您将获得预期的NullPointerException。

答案 1 :(得分:8)

如果您将代码更改为使用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。

无论如何,在构建Optional.of返回的值时,我想您想知道为什么Optional.ofNullable被用来代替findAny() ...

好吧,我只能推测,但我认为findAny()findFirst()旨在找到符合某些条件的值,即Person,其名称以{{1}开头}。您可能希望知道您的信息流中是否有A个元素。但在这种情况下,你不需要真正找到这样的元素,因为你已经知道,如果你找到它,它就会......嗯......只是null。因此,如果您的信息流包含null,那么检查就足够了,您可以完全使用null查找是否属于这种情况。

换句话说,找到一个anyMatch()的元素并不是很有用,因为你无法对它做任何事情(除了知道它之外) null)。

编辑2:正如用户@ holi-java在下面的评论中指出,如果null返回findAny(),则无法知道{{1}找到与否。在这种情况下,结果将是不明确的,因为Optional.ofNullable(null),即它会导致混淆,因为null,意味着找不到匹配的值。

答案 2 :(得分:2)

这不是一个错误,它是在get()的实例上调用Optional而导致NPE的结果。导致它的确切调用是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:

  

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

您可以使用anyMatch()

达到预期效果
Arrays.asList(null, null, 1).stream().anyMatch(obj -> obj == null)

为什么在ofNullable()

的实施中未使用findAny()

API的设计者不想假设null是否表示该值不存在(缺少值)或存在但是等于null。此外,您仍然可以在任何信息流上使用map(Optional::isNullable)

答案 3 :(得分:2)

Here's findAny()的文档,这就是它所说的:

  

引发:NullPointerException -

     

如果所选元素为空

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

您可以使用anyMatch代替,例如:

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