java 8 stream 將 List 轉(zhuǎn)為 Map Duplicate key

目的

將 List 轉(zhuǎn)為 Map,如果有多個(gè)值對(duì)應(yīng)同一個(gè)key,則保留最后一個(gè)。

一、準(zhǔn)備

1??、構(gòu)造幾個(gè)user對(duì)象,轉(zhuǎn)為一個(gè)user的List,注意其中user2user0的id是相同的

/**
 * @description: 用戶信息
 * @author: wx
 * @create: 2019-09-15 18:27
 */
public class User {

    private Integer id;
    private String userName;
    private String password;

    public User() {
    }
    public User(Integer id, String password) {
        this.id = id;
        this.password = password;
    }
}

public static void main(String[] args) {
    User user0 = new User(0, "000");
    User user1 = new User(1, "111");
    User user2 = new User(0, "222");
    List<User> list = Arrays.asList(user0, user1, user2);
}

2??、然后將List轉(zhuǎn)為,以id為key,整個(gè)user對(duì)象為value的Map,加入如下代碼

Map<Integer, User> collect = list.stream()
                         .collect(Collectors.toMap(User::getId, listSub -> listSub));

3??、會(huì)發(fā)現(xiàn)報(bào)如下異常

Exception in thread "main" java.lang.IllegalStateException: 
                        Duplicate key User(id=0, userName=null, password=000)

二、解決辦法

修改代碼List轉(zhuǎn)Map代碼如下:

Map<Integer, User> collect = list.stream().collect(
        Collectors.toMap(User::getId, listSub -> listSub,
                (listSubOld, listSubNew) -> listSubNew)
);

得到的結(jié)果:

{
    0=User(id=0, userName=null, password=222), 
    1=User(id=1, userName=null, password=111)
}

三、分析

1、打開Collectors源碼看,會(huì)發(fā)現(xiàn)toMap一共有三個(gè)重寫的方法,其中根方法如下,注意看看中文注釋:

/**
* @param keyMapper     a mapping function to produce keys
*                      指定key
* @param valueMapper   a mapping function to produce values
*                      指定values
* @param mergeFunction a merge function, used to resolve collisions between
*                      values associated with the same key, as supplied
*                      to {@link Map#merge(Object, Object, BiFunction)}
*                      一個(gè)合并函數(shù),有相同的key的時(shí)候如何選取value
* @param mapSupplier   a function which returns a new, empty {@code Map} into
*                      which the results will be inserted
*                      一個(gè)函數(shù),它返回一個(gè)新的、帶有結(jié)果的空Map 
*                     指定返回的是HashMap or ConcurrentHashMap等等
*/
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);
}

2、而我一開始用的是如下重寫的toMap:

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

可以看到使用了throwingMerger()這樣一個(gè)合并的方法,再看看這方法的源碼:

private static <T> BinaryOperator<T> throwingMerger() {
    return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
}

可以看到剛剛異常拋出的信息了。
總結(jié)一下:就是一旦出現(xiàn)一個(gè)key值有兩個(gè)對(duì)應(yīng)的value,就需要進(jìn)行合并處理,但是默認(rèn)的合并方法是throwingMerger(),只要需要合并就拋出異常。
那么就找到解決辦法了,不使用默認(rèn)的方法,自己寫一個(gè)合并的方法。
如上就是lambda表達(dá)式(listSubOld, listSubNew) -> listSubNew,就是兩個(gè)輸入?yún)?shù)(一個(gè)相同的key對(duì)應(yīng)的兩個(gè)value),返回后一個(gè)值。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,914評(píng)論 0 13
  • //Clojure入門教程: Clojure – Functional Programming for the J...
    葡萄喃喃囈語閱讀 4,044評(píng)論 0 7
  • Stream是Java 8 提供的高效操作集合類(Collection)數(shù)據(jù)的API。 1. 從Iterator到...
    nkcoder閱讀 5,753評(píng)論 2 24
  • Java集合類可用于存儲(chǔ)數(shù)量不等的對(duì)象,并可以實(shí)現(xiàn)常用的數(shù)據(jù)結(jié)構(gòu)如棧,隊(duì)列等,Java集合還可以用于保存具有映射關(guān)...
    小徐andorid閱讀 2,081評(píng)論 0 13
  • 本系列出于AWeiLoveAndroid的分享,在此感謝,再結(jié)合自身經(jīng)驗(yàn)查漏補(bǔ)缺,完善答案。以成系統(tǒng)。 Java基...
    濟(jì)公大將閱讀 1,616評(píng)論 1 6

友情鏈接更多精彩內(nèi)容