当需要将一个List转换为Map时,可以使用 Java 8 中的 Collectors.toMap() 方法,Map是由key-value组成的键值对集合,在使用Collectors.toMap() 方法时,如果值为空,会报空指针异常,下面通过一个实例来验证一下。

首先定义一个 Student.java

package com.magic.npe;public class Student {private String name;private Integer age;public Student(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}
}

再创建一个 Test.java 类,用来验证将 List 转换为 Map<String, Integer>。

package com.magic.npe;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;public class Test {public static void main(String[] args) {List<Student> students = new ArrayList<>();students.add(new Student("张三", 18));students.add(new Student("李四", 21));students.add(new Student("王五", null));Map<String, Integer> studentMap = students.stream().collect(Collectors.toMap(Student::getName, Student::getAge));System.out.println(studentMap);}
}

运行程序,直接报出如下的错误信息

Exception in thread "main" java.lang.NullPointerExceptionat java.util.HashMap.merge(HashMap.java:1224)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:1374)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.magic.npe.Test.main(Test.java:16)

查看一下 Collectors.toMap() 方法的源码,如下:

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);
}

默认会创建一个 HashMap,继续查看源码:

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;
}

可以看到,在 merge() 方法中,要求 value 值不能为空

Objects.requireNonNull(value);

继续查看一下 Objects.requireNonNull() 方法的源码

public static <T> T requireNonNull(T obj) {if (obj == null)throw new NullPointerException();return obj;
}

如果值为空,则会直接报出 NullPointerException 异常。

那么,对于这个空指针异常问题,如何解决呢?一般有两种方式:

(1)替换空值null为一个默认值,比如0

package com.magic.npe;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;public class Test {public static void main(String[] args) {List<Student> students = new ArrayList<>();students.add(new Student("张三", 18));students.add(new Student("李四", 21));students.add(new Student("王五", null));Map<String, Integer> studentMap = students.stream().collect(Collectors.toMap(Student::getName, s -> Optional.ofNullable(s.getAge()).orElse(0)));System.out.println(studentMap);}
}

运行程序,输出结果如下:

{李四=21, 张三=18, 王五=0}

(2)调用 collect() 的其他实现方法

package com.magic.npe;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class Test {public static void main(String[] args) {List<Student> students = new ArrayList<>();students.add(new Student("张三", 18));students.add(new Student("李四", 21));students.add(new Student("王五", null));Map<String, Integer> studentMap = students.stream().collect(HashMap::new, (map, student) -> map.put(student.getName(), student.getAge()), HashMap::putAll);System.out.println(studentMap);}
}

运行程序,输出结果如下:

{李四=21, 张三=18, 王五=null}

Java 8中Collectors.toMap空指针异常源码分析相关推荐

  1. Hhadoop-2.7.0中HDFS写文件源码分析(二):客户端实现(1)

    一.综述 HDFS写文件是整个Hadoop中最为复杂的流程之一,它涉及到HDFS中NameNode.DataNode.DFSClient等众多角色的分工与合作. 首先上一段代码,客户端是如何写文件的: ...

  2. 【kafka】Kafka中的动态配置源码分析

    1.概述 2.源码分析 Broker启动加载动态配置 KafkaServer.startup 启动加载动态配置总流程 2.1 动态配置初始化 config.dynamicConfig.initiali ...

  3. suricata中DPDK收发包源码分析2

    <suricata中DPDK收发包源码分析1>中分析了整体的DPDK收发包框架代码,今天我们继续来深入了解一下一些细节方面的问题. 目录 Q1:收发包线程模式在代码中是怎样确定的? Q2: ...

  4. Java 8中Collectors.groupingBy方法空指针异常源码分析

    现在有这样的一个需求:老板让把所有的员工按年龄进行分组,然后统计各个年龄的人数. 这个需求,如果是在数据库中,可以直接使用一个 group by 语句进行统计即可,那么在 Java 中的话,可以借助于 ...

  5. java中Mark接口_JVM源码分析之Java对象头实现

    原标题:JVM源码分析之Java对象头实现 原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 "365篇原创计划"第十一篇. 今天呢!灯塔君跟大家讲: JVM源码分析之Ja ...

  6. java中jcl,spring-jcl 日志源码分析

    1.spring-jcl介绍 JCL全称:Jakarta Commons Logging spring-jcl 采用了设计模式中的"适配器模式",它对外提供统一的接口,然后在适配类 ...

  7. ThreadPoolExecutor的应用和实现分析(中)—— 任务处理相关源码分析 线程利用(转)...

    前面一篇文章从Executors中的工厂方法入手,已经对ThreadPoolExecutor的构造和使用做了一些整理.而这篇文章,我们将接着前面的介绍,从源码实现上对ThreadPoolExecuto ...

  8. Java线程池(3)- JUC Executors 源码分析

    4.JUC Executors 使用&源码分析 未完待续,写作中- 1.JUC里有几种线程池?各自的使用场景? FixedThreadPool public static ExecutorSe ...

  9. Java集合框架之接口Collection源码分析

    本文我们主要学习Java集合框架的根接口Collection,通过本文我们可以进一步了解Collection的属性及提供的方法.在介绍Collection接口之前我们不得不先学习一下Iterable, ...

最新文章

  1. python中文编码是什么_Python编码有什么解释吗?
  2. android 实现磨砂效果_Android 5.0 下毛玻璃(磨砂)效果如何实现?
  3. 【Linux】一步一步学Linux——cat/tac命令(38)
  4. ubuntu16.04下面xfce4没有声音
  5. Maven打包排除某个资源或者目录
  6. 中科院战略咨询院与戴尔发布《产业数字化转型:战略与实践》研究报告
  7. Sdut 2165 Crack Mathmen(数论)(山东省ACM第二届省赛E 题)
  8. python3读取excel方法封装_python-excel读写封装
  9. c语言除法的编译,怎样代替除法指令
  10. MongoDB运行状态、性能监控,分析
  11. oracle 转成sql server,怎样把Oracle查询转换为SQL Server
  12. 电脑打字学习_新手如何学会电脑打字 走上盲打之路
  13. vc830l 说明书_有了解vc830l万用表使用方法的吗?
  14. 数据库建模多表一对多和多对一、一对一、多对多
  15. 头歌-自己动手画CPU(第六关)-MIPS RAM设计-Logisim
  16. 李阳音标速成MP3文本
  17. 树莓派3B+:串口通讯
  18. 耳麦没声音,耳麦不能说话
  19. 一题乱作出来的题? ?
  20. jq简单实现点击按钮跳转页面到指定tab内容

热门文章

  1. C# 成员默认访问权限(public、private、protected、internal)
  2. 王姨劝我学HarmonyOS鸿蒙2.0系列教程之一环境搭建跑起来模拟器!
  3. 10009---59条令人捧腹但真实的程序员编程语录
  4. 算法将成为人工智能时代的“科技原力”
  5. Spring boot Failed to bind properties under ‘XXX‘问题
  6. mysql set password_MySQL修改用户的密码(SET PASSWORD)的例子
  7. POJ1830开关问题
  8. 为什么计算机桌面下面没有显示不出来,电脑底下一排图标没了,桌面底部任务栏不见了...
  9. 我博士科研经历中的经验和教训——朱亮
  10. 如何写出完美的复试简历?没有科研竞赛经历怎么办?老师喜欢什么样的学生?跨考生?//2021-2-5