Home > Software design >  Exception in Stream.anyMatch
Exception in Stream.anyMatch

Time:06-30

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.

CodePudding user response:

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.

CodePudding user response:

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.

  • Related