Java 8中Collectors.toMap空指針異常源碼解析
引言
當(dāng)需要將一個(gè)List轉(zhuǎn)換為Map時(shí),可以使用 Java 8 中的 Collectors.toMap() 方法,Map是由key-value組成的鍵值對(duì)集合,在使用Collectors.toMap() 方法時(shí),如果值為空,會(huì)報(bào)空指針異常,下面通過(guò)一個(gè)實(shí)例來(lái)驗(yàn)證一下。
Student.java 類(lèi)
首先定義一個(gè) Student.java 類(lèi)
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 類(lèi)創(chuàng)建
再創(chuàng)建一個(gè) Test.java 類(lèi),用來(lái)驗(yàn)證將 List<Student> 轉(zhuǎn)換為 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);
}
}運(yùn)行程序,直接報(bào)出如下的錯(cuò)誤信息
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()
查看一下 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);
}默認(rèn)會(huì)創(chuàng)建一個(gè) HashMap,繼續(xù)查看源碼:
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);
}通過(guò) Map.merge() 方法來(lái)合并,源碼如下:
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);
繼續(xù)查看一下 Objects.requireNonNull() 方法的源碼
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}NullPointerException 異常
如果值為空,則會(huì)直接報(bào)出 NullPointerException 異常。
那么,對(duì)于這個(gè)空指針異常問(wèn)題,如何解決呢?一般有兩種方式:
(1)替換空值null為一個(gè)默認(rèn)值,比如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));
// 如果age為null,則直接賦值默認(rèn)值0
Map<String, Integer> studentMap = students.stream().collect(Collectors.toMap(Student::getName, s -> Optional.ofNullable(s.getAge()).orElse(0)));
System.out.println(studentMap);
}
}運(yùn)行程序,可以看到如下輸出
{李四=21, 張三=18, 王五=0}
(2)調(diào)用 collect() 的其他實(shí)現(xiàn)方法
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);
}
}運(yùn)行程序,可以看到如下輸出
{李四=21, 張三=18, 王五=null}
以上就是Java 8中Collectors.toMap空指針異常源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Java8 Collectors.toMap空指針異常的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot異步線程父子線程數(shù)據(jù)傳遞的5種方式
這篇文章主要介紹了SpringBoot異步線程父子線程數(shù)據(jù)傳遞的5種方式,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-08-08
SpringBoot?Security使用MySQL實(shí)現(xiàn)驗(yàn)證與權(quán)限管理
安全管理是軟件系統(tǒng)必不可少的的功能。根據(jù)經(jīng)典的“墨菲定律”——凡是可能,總會(huì)發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會(huì)出現(xiàn)問(wèn)題,這篇文章主要介紹了SpringBoot安全管理Spring?Security基本配置2022-11-11
Java接收text/event-stream格式數(shù)據(jù)的詳細(xì)代碼
這篇文章主要介紹了java接收text/event-stream格式數(shù)據(jù),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07
Java面向?qū)ο笾畣卫O(shè)計(jì)模式詳解
這篇文章主要介紹了Java面向?qū)ο笾畣卫O(shè)計(jì)模式詳解,所謂類(lèi)的單例設(shè)計(jì)模式,就是采取一定的方法保證在整個(gè)的軟件系統(tǒng)中,對(duì)某個(gè)類(lèi)只能存在一個(gè)對(duì)象實(shí)例,并且該類(lèi)只提供一個(gè)取得其對(duì)象實(shí)例的方法,需要的朋友可以參考下2024-01-01
詳解使用Spring Cloud Consul實(shí)現(xiàn)服務(wù)的注冊(cè)和發(fā)現(xiàn)
這篇文章主要介紹了詳解使用Spring Cloud Consul實(shí)現(xiàn)服務(wù)的注冊(cè)和發(fā)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
Java時(shí)間戳類(lèi)Instant的使用詳解
這篇文章主要為大家詳細(xì)介紹了Java中時(shí)間戳類(lèi)Instant的使用方法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定幫助,需要的可以參考一下2022-09-09

