当需要将一个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
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 students = new ArrayList<>();
students.add(new Student("张三", 18));
students.add(new Student("李四", 21));
students.add(new Student("王五", null));
Map studentMap = students.stream().collect(Collectors.toMap(Student::getName, Student::getAge));
System.out.println(studentMap);
}
}
运行程序,直接报出如下的错误信息
Exception in thread "main" java.lang.NullPointerException
at 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
Collector> toMap(Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper,
BinaryOperator mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
默认会创建一个 HashMap
,继续查看源码:
public static >
Collector toMap(Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper,
BinaryOperator mergeFunction,
Supplier mapSupplier) {
BiConsumer 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 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 students = new ArrayList<>();
students.add(new Student("张三", 18));
students.add(new Student("李四", 21));
students.add(new Student("王五", null));
// 如果age为null,则直接赋值默认值0
Map 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 students = new ArrayList<>();
students.add(new Student("张三", 18));
students.add(new Student("李四", 21));
students.add(new Student("王五", null));
Map studentMap = students.stream().collect(HashMap::new, (map, student) -> map.put(student.getName(), student.getAge()), HashMap::putAll);
System.out.println(studentMap);
}
}
运行程序,可以看到如下输出
{李四=21, 张三=18, 王五=null}