Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I have some code that is playing with the java
stream
api:
boolean isAuthorized = authorizationByTenant.stream()
.filter(auth -> auth.getTenantName().equalsIgnoreCase(tenant))
.map(auth -> auth.getAuthorizedRoutes().get(component))
.flatMap(Collection::stream)
.anyMatch(routeDefinition -> isMatchingRoute(routePath, routeDefinition));
And I sometime get an Exception
pointing to the anyMatch
line:
java.lang.NullPointerException: null at
java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:273)
~[na:na] at
java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
~[na:na] at
java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
~[na:na] at
java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1602)
~[na:na] at
java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129)
~[na:na] at
java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527)
~[na:na] at
java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)
~[na:na] at
java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
~[na:na] at
java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230)
~[na:na] at
java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:196)
~[na:na] at
java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
~[na:na] at
java.base/java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:632)
~[na:na] at
com.mycompany.routefilter.functionality.FunctionalityService.isAuthorizedRoute(FunctionalityService.java:55)
~[classes!/:1.0-SNAPSHOT] at
My question here is what is null
? Is it routeDefinition
? And why does it make the call fails ? I expect that if routeDefinition
is null my method isMatchingRoute
would return false.
Thank you.
–
The NullPointerException is occurring in your .flatMap(Collection::stream)
expression.
I created a similar example and expanded the method reference into a lambda. When causing a null value there you will see the stacktrace become more clear.
Example:
Stream.of("foo")
.map(foo -> (List<String>) null)
.flatMap(Collection::stream)
.anyMatch(string -> "gnarly".equals(string)); // LINE 13
Leads to
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:271)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.stream.Streams$StreamBuilderImpl.tryAdvance(Streams.java:397)
at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127)
at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230)
at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:196)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:528)
at Test.main(Test.java:13)
When I replace it with:
Stream.of("foo")
.map(foo -> (List<String>) null)
.flatMap(strings -> strings.stream()) // LINE 11
.anyMatch(string -> "gnarly".equals(string)); // LINE 12
Then the exception becomes:
Exception in thread "main" java.lang.NullPointerException
at Test.lambda$main$1(Test.java:11)
at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:271)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.stream.Streams$StreamBuilderImpl.tryAdvance(Streams.java:397)
at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127)
at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230)
at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:196)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:528)
at Test.main(Test.java:12)
Here you see at the top of the stack trace that the real cause is in line 11. A bit confusing indeed, but I guess the JRE cannot report exceptions occurring within method references with line number accuracy.
EDIT: Regarding solutions, my IntelliJ suggests the following:
The filter:
.filter(Objects::nonNull)
.flatMap(Collection::stream)
The null safe lambda:
.flatMap(strings -> strings != null ? strings.stream() : null)
Your code is mainly failing at .flatMap(Collection::stream)
.
This is mostly because you are not handling null check in .map(auth -> auth.getAuthorizedRoutes().get(component))
. So to avoid this scenario, you can either do filter before calling flatmap:
boolean isAuthorized = authorizationByTenant.stream()
.filter(auth -> auth.getTenantName().equalsIgnoreCase(tenant))
.map(auth -> auth.getAuthorizedRoutes().get(component))
.filter(auth -> auth.getAuthorizedRoutes().get(component)!= null)
.flatMap(Collection::stream)
.anyMatch(routeDefinition -> isMatchingRoute(routePath, routeDefinition));
The hint which I have found out is based on java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230) ~[na:na] at
line of stacktrace.
MatchOps$MatchOp
is accepting predicate and determines if elements of source stream (in your case stream generated from flatMap
) matches predicate or not. So this confirms that your flatMap is generating null
value which in turn takes input of your map
call.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.