18

I am having trouble figuring why findAny() throws a null pointer exception after filter() operation on a stream. In this particular test case, the filter operation should have filtered out everything, leaving no results for findAny().

Optional<JsonNode> encryption = sseEncryptionList.stream()
                  .filter(n -> n.textValue().equals("AES256")) //Filters out everything
                  .findAny(); //Throws null pointer exception

The stack trace:

Exception in thread "main" java.lang.NullPointerException
at example.Main.lambda$main$0(Main.java:41)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:174)
at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1351)
at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
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 example.Main.main(Main.java:42)

Is this expected behavior for findAny() to throw a null pointer exception if the stream doesn't contain any elements?

Edit: What is an elegant and functional way to resolve filter operations that might filter out all elements?

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
mrQWERTY
  • 4,039
  • 13
  • 43
  • 91
  • 3
    Possible duplicate of [Why does findFirst() throw a NullPointerException if the first element it finds is null?](https://stackoverflow.com/questions/32466799/why-does-findfirst-throw-a-nullpointerexception-if-the-first-element-it-finds) – Nir Alfasi Nov 02 '17 at 18:17
  • 1
    well if you want to filter nulls, just use `filter(Objects::nonNull)` as I said in the answer. – Eugene Nov 02 '17 at 18:34

3 Answers3

16

The best way to avoid NPE is:

Optional<JsonNode> encryption = sseEncryptionList.stream()
              .filter(Objects::nonNull)
              .filter(n -> "AES256".equals(n.textValue()))
              .findAny();

"AES256".equals(n.textValue())) will not throw NPE if n.textValue() is null

Yegor Babarykin
  • 705
  • 3
  • 12
6

Your confusion comes from the fact that you filter first - and you would expect the filter method to be somewhere in the stack trace; but notice that intermediate operations do nothing per-se, they are executed lazily and only kick in when a terminal operation is present (such as findAny in your case). It's actually there in the stack trace (the filter method), but it looks like this: Example.Main.lambda$main$0(Main.java:41).

If you want to filter null values, first do:

.filter(Objects::nonNull)
.filter(n -> n.textValue().equals("AES256"))
.findAny()
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • 1
    Actually filter'ing lambda is in the stack trace (`at example.Main.lambda$main$0(Main.java:41)`) - so the exception is thrown there. `findAny` just happens to be the outermost function in the trace. – Cthulhu Nov 02 '17 at 18:22
  • @Cthulhu thx, that's what I meant. hard to change a diaper and answer SO :) will edit... – Eugene Nov 02 '17 at 18:24
  • What happens when n.textValue() return null? – Yegor Babarykin Nov 02 '17 at 19:08
  • @YegorBabarykin take a guess what happens when you call a method on an null reference :) – Eugene Nov 02 '17 at 19:09
  • 1
    I mean then `filter(Objects::nonNull)` is required, but next line can throw NPE when `n.textValue()` return `null` – Yegor Babarykin Nov 02 '17 at 19:24
  • 1
    @YegorBabarykin you are correct, you could simply invert the equals in such a case: `n -> "AES256".equals(n.textValue())` – Eugene Nov 02 '17 at 19:47
2

No, it's not the behavior, when the stream doesn't contain any elements. In which case it instead returns an Optional.empty().

Also, the NPE is the cause of a null value in the stream, as stated in the javadocs:

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
Community
  • 1
  • 1
Naman
  • 27,789
  • 26
  • 218
  • 353