Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Streams: find if stream contains null

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.

like image 815
tkachuko Avatar asked Jun 01 '17 18:06

tkachuko


People also ask

How do I check if a stream is not null?

1.1 Java Stream Filter or using the static nonNull() method provided by the java. util. Objects class. This method returns true if the allocated reference is not null, otherwise false.

How do I filter null values in stream?

We can use lambda expression str -> str!= null inside stream filter() to filter out null values from a stream.

How do I know if my Java 8 stream is empty?

You have to consume the stream to find out if it's empty. That's the point of Stream's semantics (laziness). To check that the stream is not empty you have to attempt to consume at least one element. At that point the stream has lost its "virginity" and cannot be consumed again from the start.

What happens if stream is empty Java?

Return Value : Stream empty() returns an empty sequential stream. Note : An empty stream might be useful to avoid null pointer exceptions while callings methods with stream parameters.


2 Answers

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.

like image 132
GAdams Avatar answered Nov 10 '22 03:11

GAdams


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.

like image 21
fps Avatar answered Nov 10 '22 01:11

fps