欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java8 中使用Stream 讓List 轉(zhuǎn) Map使用問題小結(jié)

 更新時(shí)間:2021年06月16日 14:59:32   作者:Kevin.ZhangCG  
這篇文章主要介紹了Java8 中使用Stream 讓List 轉(zhuǎn) Map使用總結(jié),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

在使用 Java 的新特性 Collectors.toMap() 將 List 轉(zhuǎn)換為 Map 時(shí)存在一些不容易發(fā)現(xiàn)的問題,這里總結(jié)一下備查。

空指針風(fēng)險(xiǎn)

java.lang.NullPointerException

當(dāng) List 中有 null 值的時(shí)候,使用 Collectors.toMap() 轉(zhuǎn)為 Map 時(shí),會報(bào) java.lang.NullPointerException,如下:

List<SdsTest> sdsTests = new ArrayList<>();
    SdsTest sds1 = new SdsTest("aaa","aaa");
    SdsTest sds2 = new SdsTest("bbb",null);

    sdsTests.add(sds1);
    sdsTests.add(sds2);

    Map<String, String> map = sdsTests.stream().collect(Collectors.toMap(SdsTest::getName, SdsTest::getAge));    
    System.out.println(map.toString());

---------
運(yùn)行錯(cuò)誤:
Exception in thread "main" java.lang.NullPointerException
    at java.util.HashMap.merge(HashMap.java:1216)
    at java.util.stream.Collectors.lambda$toMap$150(Collectors.java:1320)
    .....

  原因是toMap()方法中使用Map.merge()方法合并時(shí),merge 不允許 value 為 null 導(dǎo)致的,源碼如下:

default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
    Objects.requireNonNull(remappingFunction);
    // 在這里判斷了value不可為null
    Objects.requireNonNull(value);
    V oldValue = get(key);
    V newValue = (oldValue == null) ? value : remappingFunction.apply(oldValue, value);
    ...

解決方法

業(yè)務(wù)控制不要出現(xiàn) Null 值【有 Null 的地方,可以賦值默認(rèn)值】在轉(zhuǎn)換時(shí)加判斷,如果為 null,則給一個(gè)默認(rèn)值

Map<String, String> map = sdsTests.stream().collect(Collectors.toMap(SdsTest::getName, sdsTest -> sdsTest.getAge() == null ? "0" : sdsTest.getAge()));

使用 collect(..) 構(gòu)建,允許空值

Map<String, String> nmap = sdsTests.stream().collect(HashMap::new,(k, v) -> k.put(v.getName(), v.getAge()), HashMap::putAll);
// TODO 下游業(yè)務(wù)從Map取值要做NPE判斷

使用 Optional 對值進(jìn)行包裝

Map<String, Optional<String>> opmap = sdsTests.stream().collect(Collectors.toMap(SdsTest::getName, sdsTest -> Optional.ofNullable(sdsTest.getAge())));
System.out.println("bbb.age=" + opmap.get("bbb").orElse("0"));
------------
輸出:
bbb.age=0

建議

  • 優(yōu)先業(yè)務(wù)控制,盡量避免 List 中存在 Null
  • 其次推薦第 4 種方法【使用 Optional 對值進(jìn)行包裝】,能很好的避免 NPE 問題

key重復(fù)風(fēng)險(xiǎn)

java.lang.IllegalStateException: Duplicate key xx

當(dāng) List 中有重復(fù)值的時(shí)候,使用 Collectors.toMap() 轉(zhuǎn)為 Map 時(shí),會報(bào):java.lang.IllegalStateException: Duplicate key xx,例如

List<SdsTest> sdsTests = new ArrayList<>();
    SdsTest sds1 = new SdsTest("aaa","aaa");
    SdsTest sds2 = new SdsTest("aaa","ccc");

    sdsTests.add(sds1);
    sdsTests.add(sds2);

    Map<String, String> map = sdsTests.stream().collect(Collectors.toMap(SdsTest::getName, SdsTest::getAge));    
    System.out.println(map.toString());

---------
運(yùn)行錯(cuò)誤:
Exception in thread "main" java.lang.IllegalStateException: Duplicate key aaa
        at java.util.stream.Collectors.lambda$throwingMerger$92(Collectors.java:133)
        at java.util.stream.Collectors$$Lambda$6/1177096266.apply(Unknown Source)
        at java.util.HashMap.merge(HashMap.java:1245)
            .....

原因是兩個(gè)參數(shù)的toMap(xx, xx)方法, 當(dāng)出現(xiàn)重復(fù)key觸發(fā)merge時(shí),直接拋出異常。源碼如下:

public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                            Function<? super T, ? extends U> valueMapper) {
     // 注意這里的throwingMerger()
     return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}

接下來我們看throwingMerger() 方法:【注意方法注釋】

/**
 * Returns a merge function, suitable for use in
 * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or
 * {@link #toMap(Function, Function, BinaryOperator) toMap()}, which always
 * throws {@code IllegalStateException}.  This can be used to enforce the
 * assumption that the elements being collected are distinct.
 *
 * @param <T> the type of input arguments to the merge function
 * @return a merge function which always throw {@code IllegalStateException}
 */
 private static <T> BinaryOperator<T> throwingMerger() {
      return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
 }
...

解決方法

  • 業(yè)務(wù)控制盡量不要出現(xiàn)重復(fù)值
  • 出現(xiàn)重復(fù) key 時(shí),使用后面的 value 覆蓋前面的 value
SdsTest sds1 = new SdsTest("aaa","aaa");
SdsTest sds2 = new SdsTest("bbb","bbb");
SdsTest sds3 = new SdsTest("aaa","ccc");

sdsTests.add(sds1);
sdsTests.add(sds2);
sdsTests.add(sds3);

// 寫法一
Map<String, String> nmap = sdsTests.stream().collect(HashMap::new,(k, v) -> k.put(v.getName(), v.getAge()), HashMap::putAll);
System.out.println("nmap->:" + nmap.toString());

// 寫法二
Map<String, String> nmap1 = sdsTests.stream().collect(Collectors.toMap(SdsTest::getName, SdsTest::getAge, (k1, k2) -> k2));
System.out.println("nmap1->:" + nmap1.toString());
...
----------------------
輸出:
nmap->:{aaa=ccc, bbb=bbb}
nmap1->:{aaa=ccc, bbb=bbb}

出現(xiàn)重復(fù) key 時(shí),把對應(yīng)的 value 拼接起來

...
Map<String, String> nmap1 = sdsTests.stream().collect(Collectors.toMap(SdsTest::getName, SdsTest::getAge, (k1, k2) -> k1 + "," + k2));
System.out.println("nmap1->:" + nmap1.toString());
...
----------------
輸出:
nmap1->:{aaa=aaa,ccc, bbb=bbb}

把重復(fù) key 的值拼成一個(gè)集合

......
Map<String, List<String>> map = sdsTests.stream().collect(Collectors.toMap(SdsTest::getName,
    s -> {
        List<String> ages = new ArrayList<>();
        ages.add(s.getAge());
        return ages;
    },
    (List<String> v1, List<String> v2) -> {
        v1.addAll(v2);
        return v1;
    }));
System.out.println("map->"+map.toString());
------------
輸出:
map->{aaa=\[aaa, ccc\], bbb=\[bbb\]}

建議:

  • 優(yōu)先業(yè)務(wù)控制,盡量避免 List 中出現(xiàn)重復(fù)
  • 若存在重復(fù)場景,則根據(jù)實(shí)際業(yè)務(wù)場景選擇具體方法【覆蓋、拼接、搞成集合】

以上就是Java8 中使用Stream 讓List 轉(zhuǎn) Map使用總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Java8 List 轉(zhuǎn) Map使用的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解微信小程序 同步異步解決辦法

    詳解微信小程序 同步異步解決辦法

    這篇文章主要介紹了詳解微信小程序 同步異步解決辦法的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Java?@SpringBootApplication注解深入解析

    Java?@SpringBootApplication注解深入解析

    這篇文章主要給大家介紹了關(guān)于Java?@SpringBootApplication注解的相關(guān)資料,@SpringBootApplication這個(gè)注解是Spring?Boot項(xiàng)目的基石,創(chuàng)建SpringBoot項(xiàng)目之后會默認(rèn)在主類加上,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-02-02
  • SpringBoot項(xiàng)目中引入本地JAR包配置的幾種方法

    SpringBoot項(xiàng)目中引入本地JAR包配置的幾種方法

    SpringBoot有時(shí)需要引入本地JAR包以便重用已有的代碼庫或者第三方庫,本文主要介紹了SpringBoot項(xiàng)目中引入本地JAR包配置的幾種方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-08-08
  • 淺析idea生成war包放入tomcat的路徑訪問問題

    淺析idea生成war包放入tomcat的路徑訪問問題

    這篇文章主要介紹了關(guān)于idea 生成war 包放入tomcat的路徑訪問問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • MyBatis如何實(shí)現(xiàn)流式查詢的示例代碼

    MyBatis如何實(shí)現(xiàn)流式查詢的示例代碼

    這篇文章主要介紹了MyBatis 如何實(shí)現(xiàn)流式查詢的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 確保SpringBoot定時(shí)任務(wù)只執(zhí)行一次的常見方法小結(jié)

    確保SpringBoot定時(shí)任務(wù)只執(zhí)行一次的常見方法小結(jié)

    在Spring Boot項(xiàng)目中,確保定時(shí)任務(wù)只執(zhí)行一次是一個(gè)常見的需求,這種需求可以通過多種方式來實(shí)現(xiàn),以下是一些常見的方法,它們各具特點(diǎn),可以根據(jù)項(xiàng)目的實(shí)際需求來選擇最合適的方法,需要的朋友可以參考下
    2024-10-10
  • springboot2.x集成swagger的方法示例

    springboot2.x集成swagger的方法示例

    這篇文章主要介紹了springboot2.x集成swagger的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • C++享元模式詳解

    C++享元模式詳解

    這篇文章主要為大家詳細(xì)介紹了C++設(shè)計(jì)模式之享元模式Flyweight,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Redis介紹和使用場景詳解

    Redis介紹和使用場景詳解

    這篇文章主要為大家詳細(xì)介紹了Redis介紹和使用場景,需要的朋友可以參考,具體內(nèi)容如下
    2018-04-04
  • RocketMQ實(shí)現(xiàn)消息分發(fā)的步驟

    RocketMQ實(shí)現(xiàn)消息分發(fā)的步驟

    RocketMQ 實(shí)現(xiàn)消息分發(fā)的核心機(jī)制是通過 Topic、Queue 和 Consumer Group 的配合實(shí)現(xiàn)的,下面給大家介紹RocketMQ實(shí)現(xiàn)消息分發(fā)的步驟,感興趣的朋友一起看看吧
    2024-03-03

最新評論