最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

java.lang.NullPointerException

當(dāng) List 中有 null 值的時(shí)候,使用 Collectors.toMap() 轉(zhuǎn)為 Map 時(shí),會(huì)報(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 對(duì)值進(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 對(duì)值進(jìn)行包裝】,能很好的避免 NPE 問(wèn)題

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

java.lang.IllegalStateException: Duplicate key xx

當(dāng) List 中有重復(fù)值的時(shí)候,使用 Collectors.toMap() 轉(zhuǎn)為 Map 時(shí),會(huì)報(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);
}

接下來(lái)我們看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);

// 寫(xiě)法一
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());

// 寫(xiě)法二
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í),把對(duì)應(yīng)的 value 拼接起來(lái)

...
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ù)場(chǎng)景,則根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景選擇具體方法【覆蓋、拼接、搞成集合】

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

相關(guān)文章

  • 詳解SpringMVC攔截器配置及使用方法

    詳解SpringMVC攔截器配置及使用方法

    本篇文章主要介紹了SpringMVC攔截器配置及使用方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • IDEA新手必備之各種快捷鍵詳解

    IDEA新手必備之各種快捷鍵詳解

    這篇文章主要介紹了IDEA新手必備之各種快捷鍵詳解,文中有非常詳細(xì)的快捷鍵介紹,對(duì)正在使用IDEA的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • 淺談一下Java線程組ThreadGroup

    淺談一下Java線程組ThreadGroup

    ThreadGroup是為了方便線程管理出現(xiàn)了,可以統(tǒng)一設(shè)定線程組的一些屬性,比如setDaemon,設(shè)置未處理異常的處理方法,設(shè)置統(tǒng)一的安全策略等等,需要的朋友可以參考下
    2023-05-05
  • Java面試題沖刺第三天--集合框架篇

    Java面試題沖刺第三天--集合框架篇

    這篇文章主要為大家分享了最有價(jià)值的三道java面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下
    2021-07-07
  • SpringBoot + 微信公眾號(hào)JSAPI支付功能的實(shí)現(xiàn)

    SpringBoot + 微信公眾號(hào)JSAPI支付功能的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot + 微信公眾號(hào)JSAPI支付功能的實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • Java中數(shù)組在內(nèi)存中存放原理的講解

    Java中數(shù)組在內(nèi)存中存放原理的講解

    今天小編就為大家分享一篇關(guān)于Java中數(shù)組在內(nèi)存中存放原理的講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-04-04
  • MyBatis框架簡(jiǎn)介及入門(mén)案例詳解

    MyBatis框架簡(jiǎn)介及入門(mén)案例詳解

    MyBatis是一個(gè)優(yōu)秀的持久層框架,它對(duì)jdbc的操作數(shù)據(jù)庫(kù)的過(guò)程進(jìn)行封裝,使開(kāi)發(fā)者只需要關(guān)注SQL本身,而不需要花費(fèi)精力去處理例如注冊(cè)驅(qū)動(dòng)、創(chuàng)建connection、創(chuàng)建statement、手動(dòng)設(shè)置參數(shù)、結(jié)果集檢索等jdbc繁雜的過(guò)程代碼,本文將作為最終篇為大家介紹MyBatis的使用
    2022-08-08
  • Spring-Security實(shí)現(xiàn)登錄接口流程

    Spring-Security實(shí)現(xiàn)登錄接口流程

    Security?是?Spring?家族中的一個(gè)安全管理框架,SpringSecurity的原理其實(shí)就是一個(gè)過(guò)濾器鏈,內(nèi)部包含了提供各種功能的過(guò)濾器,這篇文章主要介紹了Spring-Security實(shí)現(xiàn)登錄接口,需要的朋友可以參考下
    2023-05-05
  • SpringBoot實(shí)現(xiàn)國(guó)際化的操作步驟

    SpringBoot實(shí)現(xiàn)國(guó)際化的操作步驟

    國(guó)際化(Internationalization) 是指為了適應(yīng)不同語(yǔ)言、文化和地區(qū)的用戶(hù),使軟件能夠方便地進(jìn)行本地化修改的過(guò)程,本文介紹了SpringBoot 國(guó)際化功能的簡(jiǎn)單使用,感興趣的朋友可以參考下
    2024-02-02
  • Java實(shí)用技巧:如何使用String去除開(kāi)頭的第一個(gè)字符?

    Java實(shí)用技巧:如何使用String去除開(kāi)頭的第一個(gè)字符?

    這篇文章主要介紹了Java實(shí)用技巧:如何使用String去除開(kāi)頭的第一個(gè)字符,需要的朋友可以參考下
    2023-11-11

最新評(píng)論

昭觉县| 沙河市| 北宁市| 镇康县| 普陀区| 益阳市| 大冶市| 巍山| 灵璧县| 交城县| 葵青区| 浏阳市| 葫芦岛市| 思南县| 柳州市| 上杭县| 中江县| 湾仔区| 婺源县| 曲松县| 万州区| 渭源县| 洛浦县| 赫章县| 绥棱县| 鹤山市| 枣强县| 阿克| 永仁县| 昆山市| 汤阴县| 资兴市| 奉化市| 宁晋县| 林州市| 天峻县| 皮山县| 佳木斯市| 达州市| 沛县| 樟树市|