起因
编写完一个需求后在联调时出现了一个NPE异常,日志如下
java.lang.NullPointerException: null
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.Collections$2.tryAdvance(Collections.java:4719)
at java.util.Collections$2.forEachRemaining(Collections.java:4727)
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:566)
at com.xxx.xxx.service.impl.DynamicFormColumnServiceImpl.lambda$getCodePropertyValue$24(DynamicFormColumnServiceImpl.java:465)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1321)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.HashMap$EntrySpliterator.forEachRemaining(HashMap.java:1723)
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:566)
at com.xxx.xxx.service.impl.DynamicFormColumnServiceImpl.getCodePropertyValue(DynamicFormColumnServiceImpl.java:463)
对应出错的代码如下
sourceDataList.stream().collect(Collectors.toMap(
sourceData -> sourceData,
sourceData -> CommonUtil.convertType(
ReflectUtil.getFieldValue(sourceData, entry.getValue().getRowName()),
entry.getKey().getValueType().getClazz()
)
)
已知sourceDataList
不为空,且其中也没有为null
的元素,并且CommonUtil.convertType
的流程不会抛出异常
分析
根据以上信息分析可以知道,问题就发生在CommonUtil.convertType
的返回结果上
但是根据以往经验,HashMap
是允许一个key
为null
或多个value
为null
的,所以应该是其他的地方没有注意到
查看Collectors.toMap
的调用处,内容如下
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);
}
发现在Collectors.toMap
的调用过程中并不是我们平常常用的put
方法,而是merge
查看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();
int hash = hash(key);
.................
return value;
}
其中明确写到如果value
为空则抛出NPE异常
向上查看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;
}
可以看到判断方式也与HashMap
中重写的方法类似
解决
-
换用
.forEach
方法Map<T, Object> map = new HashMap<>();
sourceDataList.forEach(
sourceData -> map.put(
sourceData,
CommonUtil.convertType(
ReflectUtil.getFieldValue(sourceData, entry.getValue().getRowName()),
entry.getKey().getValueType().getClazz()
)
)
);
return map; -
写一个自定义的
Collector
(推荐)sourceDataList.stream()
.collect(Collector.of(
HashMap::new,
(map, sourceData) ->
map.put(
sourceData,
CommonUtil.convertType(
ReflectUtil.getFieldValue(sourceData, entry.getValue().getRowName()),
entry.getKey().getValueType().getClazz()
)
),
(o1, o2) -> o1
))参考
Collectors.toMap不允许Null Value导致NPE[1]
鸣谢
@黄同学————向黄同学学习!
参考资料
Collectors.toMap不允许Null Value导致NPE: https://www.cnblogs.com/larva-zhh/p/11394898.html
原文始发于微信公众号(程序员段宝):Stream流中Collectors.toMap方法内value为null导致空指针异常问题
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/235127.html