91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java8中使用Stream讓List轉Map使用問題有哪些

發布時間:2021-06-16 17:42:35 來源:億速云 閱讀:206 作者:小新 欄目:開發技術

小編給大家分享一下Java8中使用Stream讓List轉Map使用問題有哪些,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

在使用 Java 的新特性 Collectors.toMap() 將 List 轉換為 Map 時存在一些不容易發現的問題,這里總結一下備查。

空指針風險

java.lang.NullPointerException

當 List 中有 null 值的時候,使用 Collectors.toMap() 轉為 Map 時,會報 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());

---------
運行錯誤:
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()方法合并時,merge 不允許 value 為 null 導致的,源碼如下:

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);
    ...

解決方法

業務控制不要出現 Null 值【有 Null 的地方,可以賦值默認值】在轉換時加判斷,如果為 null,則給一個默認值

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

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

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

使用 Optional 對值進行包裝

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

建議

  • 優先業務控制,盡量避免 List 中存在 Null

  • 其次推薦第 4 種方法【使用 Optional 對值進行包裝】,能很好的避免 NPE 問題

key重復風險

java.lang.IllegalStateException: Duplicate key xx

當 List 中有重復值的時候,使用 Collectors.toMap() 轉為 Map 時,會報: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());

---------
運行錯誤:
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)
            .....

原因是兩個參數的toMap(xx, xx)方法, 當出現重復key觸發merge時,直接拋出異常。源碼如下:

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)); };
 }
...

解決方法

  • 業務控制盡量不要出現重復值

  • 出現重復 key 時,使用后面的 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}

出現重復 key 時,把對應的 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}

把重復 key 的值拼成一個集合

......
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\]}

建議:

  • 優先業務控制,盡量避免 List 中出現重復

  • 若存在重復場景,則根據實際業務場景選擇具體方法【覆蓋、拼接、搞成集合】

以上是“Java8中使用Stream讓List轉Map使用問題有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

东丰县| 达尔| 梅州市| 石门县| 古蔺县| 丘北县| 海南省| 闵行区| 吉林市| 乌拉特中旗| 德江县| 成武县| 通榆县| 建平县| 灵台县| 诏安县| 黄大仙区| 平乐县| 四子王旗| 贵港市| 梁河县| 门源| 梧州市| 邢台市| 亳州市| 万盛区| 江北区| 安宁市| 唐河县| 三门峡市| 广饶县| 西平县| 潮安县| 樟树市| 远安县| 额济纳旗| 偏关县| 大英县| 岐山县| 湘阴县| 扶余县|