Collectors.toMap

假設(shè)需求時這樣的

將一個對象list轉(zhuǎn)換成map

// 原數(shù)據(jù):
List<Order> orders;

// 轉(zhuǎn)換后數(shù)據(jù):
Map<Long, String> orderMaps;

list里的元素


image.png

轉(zhuǎn)換后map的key-value


image.png

現(xiàn)階段的解決方式一般有2大類

  1. java代碼里顯示使用for循環(huán)
  2. 通過stream的內(nèi)循環(huán)

先寫簡單的方案,顯示for循環(huán)如下

// 我不寫了,這個太簡單了

再來寫stream的方案

  1. 通過集合類型的.stream()函數(shù)將集合轉(zhuǎn)成流,
  2. 然后通過collect()函數(shù)收集流數(shù)據(jù),
  3. 此函數(shù)的參數(shù)是Collectors.toXXX();
    代碼如下:
準(zhǔn)備工作1,這是模擬的訂單類,湊合一下
/**
 * 模擬訂單類
 */
@Data
@AllArgsConstructor
@Accessors(chain = true)
class Order {
    private Long id;
    private String receiverName;
}
準(zhǔn)備工作2,準(zhǔn)備一個訂單集合
static List<Order> buildOrders() {
        Order order1 = new Order(1L, "李靜");
        Order order2 = new Order(2L, "沙坪");
        Order order3 = new Order(3L, "老李");

        List<Order> orders = new ArrayList<>(3);
        orders.add(order1);
        orders.add(order2);
        orders.add(order3);

        return orders;
    }

處理工作,將list轉(zhuǎn)成map

先來寫個簡易版本
// 方式1, 簡易版
        Map<Long, String> map2 = orders.stream().collect(Collectors.toMap(
                kv -> { // 處理key的函數(shù)
                    return kv.getId();
                }, 
                kv -> { // 處理value的函數(shù)
                    return kv.getReceiverName();
                }));
        // 觀察返回map的類型
        System.out.println(map2.getClass());
        map2.forEach((k, v) -> {
            System.out.println(k + "-" + v);
        });

執(zhí)行結(jié)果如下:可以發(fā)現(xiàn)返回map的類型是java.util.HashMap

class java.util.HashMap
1-李靜
2-沙坪
3-老李

再來寫一個進(jìn)階版本,這是看阿里開發(fā)手冊發(fā)現(xiàn)的

因為原集合轉(zhuǎn)換成map的過程中,有可能會出現(xiàn)key重復(fù),為了解決key重復(fù),所以Collectors.toMap函數(shù)提供了重載方法,第三個參數(shù)函數(shù)用于處理key重復(fù)

方式2,進(jìn)階版
Map<Long, String> map3 = orders.stream().collect(Collectors.toMap(
                kv -> {
                    return kv.getId();
                },
                kv -> {
                    return kv.getReceiverName();
                },
                (oldKey, newKey) -> { // 處理key重復(fù)的函數(shù)
                    System.err.println("key重復(fù),已替換");
                    return newKey;
                }));
        System.out.println(map3.getClass());
        map3.forEach((k, v) -> {
            System.out.println(k + "-" + v);
        });

執(zhí)行之前做下修改:
這里需要先將原集合,即order集合里的元素值改成如下內(nèi)容,order2與order3的id都是2L,這樣會出現(xiàn)key重復(fù)

        Order order1 = new Order(1L, "李靜");
        Order order2 = new Order(2L, "沙坪");
        Order order3 = new Order(2L, "老李");

執(zhí)行結(jié)果如下:

  1. 簡易版的執(zhí)行結(jié)果:很顯然的報出了key重復(fù)的異常

Exception in thread "main" java.lang.IllegalStateException: Duplicate key 沙坪
at java.util.stream.Collectors.lambdathrowingMerger0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1254)
at java.util.stream.Collectors.lambdatoMap58(Collectors.java:1320)
at java.util.stream.ReduceOps3ReducingSink.accept(ReduceOps.java:169) at java.util.ArrayListArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.enn.sale.crm.clue.web.Test.main(Test.java:39)

  1. 進(jìn)階版本執(zhí)行結(jié)果:沒啥問題,重復(fù)的key已經(jīng)按照代碼內(nèi)容處理了,返回map類型依然是java.util.HashMap

class java.util.HashMap
1-李靜
2-老李

再寫一個增強(qiáng)版本吧

這個版本的目的是,指定轉(zhuǎn)換后map類型,比如我不想用HashMap,我可以指定為TreeMap

Map<Long, String> map4 = orders.stream().collect(Collectors.toMap(
                kv -> {
                    return kv.getId();
                },
                kv -> {
                    return kv.getReceiverName();
                },
                (oldKey, newKey) -> {
                    System.err.println("key重復(fù),已替換");
                    return newKey;
                },
                () -> {
                    // 此處是個提供者類型的函數(shù)式接口,不用參數(shù),只返回
                    // 返回值為指定轉(zhuǎn)換后map的類型的對象
                    // 源碼注釋是這樣的,自己體會吧
                    // a function which returns a new, empty {@code Map} into
                    // * which the results will be inserted
                    return new TreeMap<>();
                }
        ));

        System.out.println(map4.getClass());
        map4.forEach((k, v) -> {
            System.out.println(k + "-" + v);
        });

執(zhí)行結(jié)果如下:返回類型已經(jīng)是java.util.TreeMap

class java.util.TreeMap
1-李靜
2-老李

本篇內(nèi)容基本上寫完了,建議在開發(fā)中盡量不要使用簡易版本,key重復(fù)這種情況很難避免

粘貼下1.8的部分源碼

/**
     * @param keyMapper a mapping function to produce keys
     * @param valueMapper a mapping function to produce 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)}
     * @param mapSupplier a function which returns a new, empty {@code Map} into
     *                    which the results will be inserted
     * @return a {@code Collector} which collects elements into a {@code Map}
     * whose keys are the result of applying a key mapping function to the input
     * elements, and whose values are the result of applying a value mapping
     * function to all input elements equal to the key and combining them
     * using the merge function
     *
     * @see #toMap(Function, Function)
     * @see #toMap(Function, Function, BinaryOperator)
     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
     */
    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)

寫完收工

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

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

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