背景

线上某任务出现报警,报错日志如下:

java.lang.NullPointerException: null
at java.util.HashMap.merge(HashMap.java:1225)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1380)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
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.xxx.web.controller.TaskController.getOmsAccidCloudCCUserIdMap(TaskController.java:648)
at com.xxx.web.controller.TaskController.executePushNewRegisterLead(TaskController.java:400)
at com.xxx.web.controller.TaskController.pushNewRegister(TaskController.java:145)

对应出错的代码:

omsAccidCloudCCUserIdMap = administratorList.stream()
.collect(Collectors.toMap(Administrator::getAccid,administrator
-> cloudccAccidUserIdMap.get(administrator.getCloudccAccid())));

已知administratorList不含有null元素,administratorListcloudccAccidUserIdMap都不为nullAdministrator::getAccid也不会返回null值。

问题定位

综上所述,NPE只可能发生在

administrator -> cloudccAccidUserIdMap.get(administrator.getCloudccAccid())

但是HashMap是允许一个null key和多个null value的啊,查看openjdk的HashMap源码,看到javadoc也是如此说明的:

Hash table based implementation of the Map interface. This implementation provides all of the optional map operations, and permits null values and the null key. (The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.) This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.

那究竟是哪里出了问题呢,回过头仔细看报错信息,发现是java.util.HashMap.merge(HashMap.java:1225)抛出的异常,查看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;
}

向上追溯,看到java.util.Map接口中对merge的定义:

/**
* If the specified key is not already associated with a value or is
* associated with null, associates it with the given non-null value.
* Otherwise, replaces the associated value with the results of the given
* remapping function, or removes if the result is {@code null}. This
* method may be of use when combining multiple mapped values for a key.
* For example, to either create or append a {@code String msg} to a
* value mapping:
*
* <pre> {@code
* map.merge(key, msg, String::concat)
* }</pre>
*
* <p>If the function returns {@code null} the mapping is removed. If the
* function itself throws an (unchecked) exception, the exception is
* rethrown, and the current mapping is left unchanged.
*
* @implSpec
* The default implementation is equivalent to performing the following
* steps for this {@code map}, then returning the current value or
* {@code null} if absent:
*
* <pre> {@code
* V oldValue = map.get(key);
* V newValue = (oldValue == null) ? value :
* remappingFunction.apply(oldValue, value);
* if (newValue == null)
* map.remove(key);
* else
* map.put(key, newValue);
* }</pre>
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties. In particular, all implementations of
* subinterface {@link java.util.concurrent.ConcurrentMap} must document
* whether the function is applied once atomically only if the value is not
* present.
*
* @param key key with which the resulting value is to be associated
* @param value the non-null value to be merged with the existing value
* associated with the key or, if no existing value or a null value
* is associated with the key, to be associated with the key
* @param remappingFunction the function to recompute a value if present
* @return the new value associated with the specified key, or null if no
* value is associated with the key
* @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map
* (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map
* (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified key is null and this map
* does not support null keys or the value or remappingFunction is
* null
* @since 1.8
*/
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;
}

可以看到,Collectors.toMap在底层使用的是Map::merge方法,而merge方法不允许null value,无论该Map实例是否支持null value(但是允许null key如果Map实例支持的话)。

@throws NullPointerException if the specified key is null and this map does not support null keys or the value or remappingFunction is null

问题解决

找到原因了,那么如何解决呢?这个问题在stackoverflow上也有一篇帖子说明了如何fix这个问题https://stackoverflow.com/questions/24630963/java-8-nullpointerexception-in-collectors-tomap

不使用Collectors.toMap,改为使用forEach遍历列表手动转换。

Collectors.toMap不允许Null Value导致NPE的更多相关文章

  1. 使用Collectors.toMap遇到NullPointerException

    这个坑也是踩过好几次了,记录一笔. 当试图使用Collectors.toMap将一个stream收集为Map的时候,若构造map的valueMapper返回null时,则会报NullPointerEx ...

  2. Java8 Collectors.toMap的坑

    按照常规思维,往一个map里put一个已经存在的key,会把原有的key对应的value值覆盖,然而通过一次线上问题,发现Java8中的Collectors.toMap反其道而行之,它默认给抛异常,抛 ...

  3. java 8 lamda Stream的Collectors.toMap 参数

    使用toMap()函数之后,返回的就是一个Map了,自然会需要key和value.toMap()的第一个参数就是用来生成key值的,第二个参数就是用来生成value值的.第三个参数用在key值冲突的情 ...

  4. java8 list转Map报错Collectors.toMap :: results in "Non-static method cannot be refernced from static context"

    1.问题:java8 list转Map 报错Collectors.toMap :: results in "Non-static method cannot be refernced fro ...

  5. MySQL为Null会导致5个问题,个个致命!

    在正式开始之前,我们先来看下 MySQL 服务器的配置和版本号信息,如下图所示: "兵马未动粮草先行",看完了相关的配置之后,我们先来创建一张测试表和一些测试数据. -- 如果存在 ...

  6. 如何优雅的使用 参数 is null而不导致全表扫描(破坏索引)

    相信大家在很多实际业务中(特别是后台系统)会使用到各种筛选条件来筛选结果集 首先添加测试数据 ), Age INT) go CREATE INDEX idx_age ON TempList (Age) ...

  7. ExceptionInChainedOperatorException:flink写hbase对于null数据导致数据导致出现异常

    使用的flink版本:1.9.1 异常描述 需求: 从kafka读取一条数据流 经过filter初次筛选符合要求的数据 然后通过map进行一次条件判断再解析.这个这个过程中可能返回null或目标输出o ...

  8. 服务器字体导致NPE

    服务器字体问题 服务器在windows下运行正常. 搬到Linux之后,注册页有个404??? HTTP Status 500 – Internal Server Error Type 异常报告 消息 ...

  9. if(response.isSuccess){}else{}的方式,如果我们由于忽略没有设置success字段的值,就可能导致

    在日常开发中,我们会经常要在类中定义布尔类型的变量,比如在给外部系统提供一个RPC接口的时候,我们一般会定义一个字段表示本次请求是否成功的. 关于这个”本次请求是否成功”的字段的定义,其实是有很多种讲 ...

随机推荐

  1. Mask-RCNN:教你如何制作自己的数据集进行像素级的目标检测

    概述 Mask-RCNN,是一个处于像素级别的目标检测手段.目标检测的发展主要历程大概是:RCNN,Fast-RCNN,Fster-RCNN,Darknet,YOLO,YOLOv2,YOLO3(参考目 ...

  2. 解决springmvc返回中文乱码问题

  3. shiro-helloworld

    1.目录结构 2.log4j.properties # # Licensed to the Apache Software Foundation (ASF) under one # or more c ...

  4. Vim、Linux、Shell、Idea、Git命令总结

    目录 Vim 剪切 复制 shell idea centos Vim /名字 搜索关键词 :u 撤销上一次操作 v 进入可视模式(选中模式) 剪切 回到顶部 命令模式下的剪切 dd,删除一整行==剪切 ...

  5. 对ThreadLocal的一些理解

    ThreadLocal也是在面试过程中经常被问到的,本文主要从以下三个方面来谈对ThreadLocal的一些理解: ThreadLocal用在什么地方 ThreadLocal一些细节 ThreadLo ...

  6. 请使用switch语句和if...else语句,计算2008年8月8日这一天,是该年中的第几天。

    请使用switch语句和if...else语句,计算2008年8月8日这一天,是该年中的第几天. #include <stdio.h> int main() { /* 定义需要计算的日期 ...

  7. Is it a full physical image???

    My friend asked me why she could not find some important files in a physical image acquired from an ...

  8. EasyUI combobox下拉列表实现搜索过滤(模糊匹配)

    项目中的某个下拉列表长达200多个项,这么巨大的数量一个一个找眼镜都得看花,于是就得整了个搜索功能.看网上别人帖子有只能前缀匹配的方案,但只能前缀匹配的话用起来也不是很方便.于是就记录一下模糊匹配的方 ...

  9. darknet是如何对数据集做resize的?

    在准备数据集时,darknet并不要求我们预先对图片resize到固定的size. darknet自动帮我们做了图像的resize. darknet训练前处理 本文所指的darknet版本:https ...

  10. jdk8与jdk7中hashMap的resize分析

    在分析代码之前,我们先抛出下面的问题: hashmap 扩容时每个 entry 需要再计算一次 hash 吗? 我们首先看看jdk7中的hashmap的resize实现 1 void resize(i ...