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)文章
Spring通過(guò)<import>標(biāo)簽導(dǎo)入外部配置文件
之前文章里我們講到Spring加載Xml配置文件的細(xì)節(jié),那么加載完了我們肯定要解析這個(gè)配置文件中定義的元素。這篇我們首先來(lái)分析下Spring是如何通過(guò)標(biāo)簽導(dǎo)入外部配置文件的。2021-06-06通過(guò)代碼示例了解submit與execute的區(qū)別
這篇文章主要介紹了通過(guò)代碼示例了解submit與execute的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09淺析SpringBoot統(tǒng)一返回結(jié)果的實(shí)現(xiàn)
前后端開(kāi)發(fā)過(guò)程中數(shù)據(jù)交互規(guī)范化是一件非常重要的事情,不僅可以減少前后端交互過(guò)程中出現(xiàn)的問(wèn)題,也讓代碼邏輯更加具有條理,下面小編就和大家講講SpringBoot如何統(tǒng)一返回結(jié)果的吧2023-07-07Java中Stream流對(duì)多個(gè)字段進(jìn)行排序的方法
我們?cè)谔幚頂?shù)據(jù)的時(shí)候經(jīng)常會(huì)需要進(jìn)行排序后再返回給前端調(diào)用,比如按照時(shí)間升序排序,前端展示數(shù)據(jù)就是按時(shí)間先后進(jìn)行排序,下面這篇文章主要給大家介紹了關(guān)于Java中Stream流對(duì)多個(gè)字段進(jìn)行排序的相關(guān)資料,需要的朋友可以參考下2023-10-10Java基于阻塞隊(duì)列實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型示例詳解
這篇文章主要介紹了Java基于阻塞隊(duì)列實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型,阻塞隊(duì)列的特點(diǎn)就是阻塞兩個(gè)字,阻塞功能使得生產(chǎn)者和消費(fèi)者兩端的能力得以平衡,當(dāng)有任何一端速度過(guò)快時(shí),阻塞隊(duì)列便會(huì)把過(guò)快的速度降下來(lái),感興趣的朋友可以參考下2023-12-12關(guān)于Spring Bean實(shí)例過(guò)程中使用反射和遞歸處理的Bean屬性填充問(wèn)題
本文帶領(lǐng)大家一起學(xué)習(xí)下在Spring Bean實(shí)例過(guò)程中如何使用反射和遞歸處理的Bean屬性填充,需要在類(lèi) AbstractAutowireCapableBeanFactory 的 createBean 方法中添加補(bǔ)全屬性方法,具體操作方法跟隨小編一起學(xué)習(xí)下吧2021-06-06