List<String> player = Arrays.asList("Lebron", "Kobe", "Shaquille"); List<String> team = Arrays.asList("Cleveland", "Los Angeles", null); Map<String, String> currentTeam = new HashMap<>();for (int i = 0; i < player.size(); i++) { currentTeam.put(player.get(i), team.get(i)); }
Everything works as expected, it inserts the null value into my map. So I tried to convert it to streams (maybe not in the best way):
Map<String, String> currentTeam = IntStream.range(0, player.size()) .mapToObj(i -> i) .collect(Collectors.toMap(i -> player.get(i), i -> team.get(i)));
Here is what I get:
Exception in thread "main" java.lang.NullPointerException at java.util.HashMap.merge(HashMap.java:1216) at java.util.stream.Collectors.lambda$toMap$148(Collectors.java:1320) at java.util.stream.Collectors$$Lambda$6/149928006.accept(Unknown Source) at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) at java.util.stream.IntPipeline$4$1.accept(IntPipeline.java:250) at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110) at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at Test.main(Test.java:23)
Is it using a kind of Map that does not accept null values? Let's check:
publicstatic<T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) {return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new); }
Well, no. It uses a standard HashMap. In the stack, the Exception is thrown from the HashMap.merge() function. So let's have a look:
@Overridepublic V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {if (value == null)thrownew NullPointerException(); ... }
So the problem is not in the type of map but in the implementation of the merge. The javadoc for the HashMap merge() method says that the value parameter is "the non-null value to be merged with the existing value associated with the key". So yes, it says it in the Javadoc, but not where you would expect it.
By the way, if you really want to make it work with streams, you would have to supply your own collector (as an aside note, the same problem arises with the groupBy collector) :
Map<String, String> currentTeam = IntStream.range(0, player.size()) .mapToObj(i -> i) .collect(HashMap::new, (map, i) -> map.put(player.get(i), team.get(i)), HashMap::putAll);
Maybe I'll stick with the loop for this time.