14

Most probably a duplicate, however I was not able to find any particular one.

Given

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

Expectation

Should at least work (i.e return false because findAny returns Optional).

Actual

NullPointerException is thrown

Question

Is it a bug or a feature?

Thanks for your opinion and explanation.

1
  • see my revised answer Commented Jun 1, 2017 at 18:59

4 Answers 4

17

If you change your code to use anyMatch instead of filter(...).findAny().isPresent(), it works as expected:

boolean found = Arrays.asList(null, null, 1)
        .stream()
        .anyMatch(Objects::isNull);

System.out.println(found); // true

As to why your version fails with NPE, in the Stream.findAny docs it says:

Throws:

NullPointerException - if the element selected is null

So this is expected behavior.


EDIT: The NPE occurs because Optional.of is used to construct the value returned by findAny(). And Optional.of requires a non-null value, as per the docs:

Returns an Optional with the specified present non-null value.

Anyways, I suppose you'd like to know why Optional.of was used instead of Optional.ofNullable, when building the value returned by findAny()...

Well, I can only speculate, but I think that findAny() and findFirst() are meant to find values that match some criteria, i.e. a Person whose name starts with A. It can be the case that you want to know whether there's a null element in your stream. But, in this case, you don't need to actually find such element, because you already know that, if you find it, it will be, well... just null. So it's enough to only check if your stream contains null, and you can perfectly use anyMatch() to find if that's the case.

In other words, it wouldn't be of much use to find an element that is null, because you can't do anything with it (apart from knowing that it's null).


EDIT 2: As user @holi-java indicates in his comment below, if findAny() returned Optional.ofNullable(null), then there would be no way to know whether null was found or not. In this case, the result would be ambiguous, because Optional.ofNullable(null).equals(Optional.empty()) == true, i.e. it would result in confusion, since Optional.ofNullable(null).isPresent() == false, meaning there was no matching value found.

Sign up to request clarification or add additional context in comments.

15 Comments

well, good job. It is another time difference to submit, ^_^.
a Optional has 2 states: absent & present. if findAny using Optional.ofNullable then it has 3 states: absent & null & present. if we want to distinct between absent and null, then we must compare with optional == Optional.empty() , and then we back to checking an object whether is null as object == null and Optional loses it role for avoid checking nulls, and can't chain a Optional with 3 states as further.
@holi-java maybe it was me that misunderstood you... I'm thinking it as follows: if findAny used Optional.ofNullable to return the found value, and if that found value was null, then you wouldn't be able to know if the value was found or not, because an Optional that has a null value is an empty Optional.
@holi-java my point is that you don't need three states with findAny, you only need two: found and not_found. For the very special case when you want to know if your stream has a null element, use anyMatch
@Federico Peralta Schaffner: well, in principle, the search condition could include null as possible result, instead of being a search for exactly null. However, this can be considered a rare corner case. I never had a need for this. Besides that, if I want to know whether a list contains null, I’d use list.contains(null) instead of using the stream API…
|
14

This behavior is highlighted in the Javadoc for findAny() https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#findAny--

Returns:an Optional describing some element of this stream, or an empty Optional if the stream is empty

Throws:NullPointerException - if the element selected is null

Since you are filtering so the Stream only contains nulls, you are getting a NullPointerException as expected.

Comments

3

Here's the documentation of findAny(), this is what it says:

Throws: NullPointerException -

if the element selected is null

So, you will always get an NPE if you try to invoke findAny() on a null object.

You can use anyMatch instead, e.g.:

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

Comments

2

It is not a bug, it is a result of calling get() on an instance of Optional which throws NPE. The exact call that causes it is findAny(), which gives the following stack trace:

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)

Also the documentation for findAny() specifies that NPE can be thrown:

Throws:NullPointerException - if the element selected is null

You can achieve the expected result using anyMatch():

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

Why ofNullable() was not used in the implementation of findAny()?

Designers of the API did not want to assume whether null means the value is not present (absent value) or is present but equals null. Also, you can still use map(Optional::isNullable) on any stream.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.