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

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í),會(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 對值進(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í),會(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);
}

接下來我們看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)文章

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

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

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

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

    這篇文章主要介紹了IDEA新手必備之各種快捷鍵詳解,文中有非常詳細(xì)的快捷鍵介紹,對正在使用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),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • Java中數(shù)組在內(nèi)存中存放原理的講解

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

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

    MyBatis框架簡介及入門案例詳解

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

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

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

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

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

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

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

最新評(píng)論

睢宁县| 天柱县| 屏东市| 清涧县| 龙南县| 许昌市| 宕昌县| 抚远县| 郴州市| 格尔木市| 布尔津县| 阜新市| 铅山县| 阳新县| 南溪县| 区。| 高州市| 嘉义市| 石景山区| 闸北区| 鄂托克前旗| 上林县| 措勤县| 洪湖市| 阜平县| 黄骅市| 房产| 托里县| 玉屏| 松滋市| 贡山| 赣州市| 浦城县| 多伦县| 乐亭县| 巴林左旗| 玉树县| 梁河县| 平顶山市| 泾川县| 孝昌县|