I am seeing some weird behaviour in Java stream API. Here's my code:
public static void main( String[] args ) {
final List<String> list = Arrays.asList( "string1", "string2" );
final Map<String, List<String>> map = new HashMap<>();
map.put( "string1", Arrays.asList( "1" ) );
//map.put( "string2", Arrays.asList( "1" ) );
Stream<String> stream = list.stream().map( map::get ).flatMap( List::stream );
System.out.println( "Stream=" stream );
long count = stream.count();
System.out.println( "Stream count=" count );
}
The second last line (long count = stream.count();
) is resulting in a NPE. The exception does not occur if I add another entry to map for key "string2" (commented code). Can somebody please point-out why it results in a NPE instead of just returning the count as 1?
The same behaviour is observed if I try to collect the stream's result in a list instead of calling count()
CodePudding user response:
Your code will call List#stream
on null in the flatMap
, which results in a NullPointerException. You need to filter out null values before the flatMap:
list.stream()
.map(map::get)
.filter(Objects::nonNull)
.flatMap(List::stream)
CodePudding user response:
.map( map::get )
when applied on the second element of your Stream ("string2") returns null
. When .flatMap( List::stream )
is applied on that null
element, you get NullPointerException
, since it tries to execute stream()
method on a null reference.
You should filter out the null
elements to avoid this:
Stream<String> stream = list.stream()
.map( map::get )
.filter(Objects::nonNull)
.flatMap( List::stream );
CodePudding user response:
Map.get() will return null
, when there is no mapping for the key in the map, as stated in the docs.
Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
To fix, filter out null elements from the stream.
Stream<String> stream = list.stream()
.map(map::get)
.filter(Objects::nonNull)
.flatMap(Collection::stream);
Or you can supply default value, using Map.getOrDefault().
Returns the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key.
Stream<String> stream = list.stream()
.map(str -> map.getOrDefault(str, Collections.emptyList()))
.flatMap(Collection::stream);
CodePudding user response:
When you do
map.get("string2")
you will get null
when you do
map.get("string2").stream()
you will get NPE
This is exactly what you are doing in your stream.
CodePudding user response:
Here
.map( map::get )
you get list containing "1"
by key "string1"
from map
, then null
by key "string2"
. This causes NPE