java 8 stream toMap key的重复问题

解决java 8 stream toMap key的重复问题

  • 问题描述
  • 原因分析:
  • 解决方案:

问题描述

工作中遇到需要将某个List里面的实体类的两个属性对应起来,比如根据姓名找到年龄,就是将List里面的entity属性解析之后放到Map里。
实体类:

public class Person {
        private String name;
        private Integer age;
        ...省略getter、setter
    }

逻辑:

		Person person = new Person("张三",20);
        Person person1 = new Person("李四",20);
        Person person2 = new Person("张三",20);

        List<Person> list = new ArrayList<Person>(){{
            add(person);
            add(person1);
            add(person2);
        }};

        Map<String, Integer> map = new HashMap<>();
        //常规写法
        for (Person p : list) {
            map.put(p.getName(), p.getAge());
        }
        System.out.println(map);
        //stream 流写法
        Map<String, Integer> collect = list.stream().collect(Collectors.toMap(Person::getName, Person::getAge));
        System.out.println(collect);

单纯常规写法肯定没什么问题,就是后面的key会被覆盖,但是stream流不行,会报错。

Exception in thread "main" java.lang.IllegalStateException: Duplicate key 20

原因分析:

Collectors.toMap这个方法其实是有三个参数的,第一个是key,第二个是value,第三个是发生冲突的合并规则。
默认采用的就是冲突之后抛出异常的处理。

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

解决方案:

只需要加上第三个参数即可

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

新代码只需要更改第三个参数即可,会跟常规写法一个效果

        Map<String, Integer> collect = list.stream().collect(Collectors.toMap(Person::getName, Person::getAge, (oldValue, newValue) -> newValue));

当然还可以采用Collectors.groupingBy(keyFunction)的写法,但是返回值会是Map>的形式。这就是新的业务场景了。
附上代码:

Map<String, List<Person>> collect1 = list.stream().collect(Collectors.groupingBy(Person::getName));

你可能感兴趣的:(工作记录,java)