Collectors.toMap

假设需求时这样的

将一个对象list转换成map

// 原数据:
List<Order> orders;

// 转换后数据:
Map<Long, String> orderMaps;

list里的元素


image.png

转换后map的key-value


image.png

现阶段的解决方式一般有2大类

  1. java代码里显示使用for循环
  2. 通过stream的内循环

先写简单的方案,显示for循环如下

// 我不写了,这个太简单了

再来写stream的方案

  1. 通过集合类型的.stream()函数将集合转成流,
  2. 然后通过collect()函数收集流数据,
  3. 此函数的参数是Collectors.toXXX();
    代码如下:
准备工作1,这是模拟的订单类,凑合一下
/**
 * 模拟订单类
 */
@Data
@AllArgsConstructor
@Accessors(chain = true)
class Order {
    private Long id;
    private String receiverName;
}
准备工作2,准备一个订单集合
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转成map

先来写个简易版本
// 方式1, 简易版
        Map<Long, String> map2 = orders.stream().collect(Collectors.toMap(
                kv -> { // 处理key的函数
                    return kv.getId();
                }, 
                kv -> { // 处理value的函数
                    return kv.getReceiverName();
                }));
        // 观察返回map的类型
        System.out.println(map2.getClass());
        map2.forEach((k, v) -> {
            System.out.println(k + "-" + v);
        });

执行结果如下:可以发现返回map的类型是java.util.HashMap

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

再来写一个进阶版本,这是看阿里开发手册发现的

因为原集合转换成map的过程中,有可能会出现key重复,为了解决key重复,所以Collectors.toMap函数提供了重载方法,第三个参数函数用于处理key重复

方式2,进阶版
Map<Long, String> map3 = orders.stream().collect(Collectors.toMap(
                kv -> {
                    return kv.getId();
                },
                kv -> {
                    return kv.getReceiverName();
                },
                (oldKey, newKey) -> { // 处理key重复的函数
                    System.err.println("key重复,已替换");
                    return newKey;
                }));
        System.out.println(map3.getClass());
        map3.forEach((k, v) -> {
            System.out.println(k + "-" + v);
        });

执行之前做下修改:
这里需要先将原集合,即order集合里的元素值改成如下内容,order2与order3的id都是2L,这样会出现key重复

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

执行结果如下:

  1. 简易版的执行结果:很显然的报出了key重复的异常

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. 进阶版本执行结果:没啥问题,重复的key已经按照代码内容处理了,返回map类型依然是java.util.HashMap

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

再写一个增强版本吧

这个版本的目的是,指定转换后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重复,已替换");
                    return newKey;
                },
                () -> {
                    // 此处是个提供者类型的函数式接口,不用参数,只返回
                    // 返回值为指定转换后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);
        });

执行结果如下:返回类型已经是java.util.TreeMap

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

本篇内容基本上写完了,建议在开发中尽量不要使用简易版本,key重复这种情况很难避免

粘贴下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)

写完收工

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容