使用Collectors.toMap()报NullPointerException
记录下最近工作中在使用
stream().collect(Collectors.toMap())出现的空指针问题
问题代码
@Test
public void test2() {
List<Student> studentList =
Stream.of(new Student("1", "张三"), new Student("2", null)).collect(Collectors.toList());
Map<String, String> map =
studentList.stream().map(student -> Pair.of(student.getUserId(), student.getUserName()))
.collect(Collectors.toMap(Pair::getKey, Pair::getValue, (v1, v2) -> v1));
System.out.println(map);
}
@Data
@AllArgsConstructor
public static class Student implements Serializable {
private static final long serialVersionUID = -3058531222330506251L;
private String userId;
private String userName;
}
java.lang.NullPointerException
at java.util.HashMap.merge(HashMap.java:1226)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
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 com.yxxmg.collection.CollectionTest.test2(CollectionTest.java:53)
按照我们正常思维逻辑这不应该会出现这个问题,想当然理解成put(key,value)方式
问题分析
-
首先分析出错代码
Map<String, String> map = studentList.stream().map(student -> Pair.of(student.getUserId(), student.getUserName())) .collect(Collectors.toMap(Pair::getKey, Pair::getValue, (v1, v2) -> v1)); -
Pair.of
/** * <p>Creates an immutable pair of two objects inferring the generic types.</p> * * <p>This factory allows the pair to be created using inference to * obtain the generic types.</p> * * @param <L> the left element type * @param <R> the right element type * @param left the left element, may be null * @param right the right element, may be null * @return a pair formed from the two parameters, not null */ public static <L, R> Pair<L, R> of(final L left, final R right) { return ImmutablePair.of(left, right); }这边可以看出key,value都可以为空
-
分析Collectors.toMap(Pair::getKey, Pair::getValue, (v1, v2) -> v1)
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction) { return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); }public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier) { BiConsumer<M, T> accumulator = (map, element) -> map.merge(keyMapper.apply(element), valueMapper.apply(element), mergeFunction); return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID); }看下
Map接口的默认merge方法default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Objects.requireNonNull(value); V oldValue = get(key); V newValue = (oldValue == null) ? value : remappingFunction.apply(oldValue, value); if(newValue == null) { remove(key); } else { put(key, newValue); } return newValue; }该接口可以看出
value不能为空,再看下我们使用的HashMap的重写的merge方法@Override public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { if (value == null) throw new NullPointerException(); if (remappingFunction == null) throw new NullPointerException(); ... return value; }从源码可以看出
value==null直接报空指针异常了
本文详细分析了在Java中使用`Stream.of().collect(Collectors.toMap())`时遇到的空指针异常,重点讨论了Pair类中的key和value可能为空导致HashMap在merge时抛出异常的情况,以及HashMap的merge方法对null值的处理机制。
1265

被折叠的 条评论
为什么被折叠?



