Java8 Collectors.toMap的坑

2022-04-27 15:02:55 2161

现在Stream Api极为常用,本文记录了list转化为map(Collectors.toMap)容易出现的坑。

    1、list中有多个元素对应的key相同,若没有处理,会抛java.lang.IllegalStateException: Duplicate key异常

    2、若value值为null,报NullPointerException。


首先我们先看一下Collectors.toMap的定义:

    Collectors.toMap有多个方法重载,如下:

toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper);

toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
        BinaryOperator<U> mergeFunction);

toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
        BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier);

参数含义分别是:

    keyMapper:Key的映射函数,用来生成key

    valueMapper:Value的映射函数,用来生成value

    mergeFunction:当Key冲突时,调用的合并方法

    mapSupplier:Map构造器,在需要返回特定的Map时使用



坑1:java.lang.IllegalStateException: Duplicate key

范例:

List<String> list = Arrays.asList("aaa", "bbb", "ccc", "aAA", "bBb", "CCc");
Map<String, String> dataMap = list.stream()
        .collect(Collectors.toMap(s -> s.toUpperCase(), s -> s.toLowerCase()));

异常:

image.png

      按照常规思维,往一个map里put一个已经存在的key,会把原有的key对应的value值覆盖。但是在使用Java8中的Collectors.toMap时,它默认给抛异常,抛异常 java.lang.IllegalStateException: Duplicate key...。


分析:

image.png

image.png


解决方案:

此时就需要使用到toMap的第三个参数了,自定义mergeFunction,如下面的 (value1,value2)->value1,

List<String> list = Arrays.asList("aaa", "bbb", "ccc", "aAA", "bBb", "CCc");
Map<String, String> dataMap = list.stream()
        .collect(Collectors.toMap(s -> s.toUpperCase(), s -> s.toLowerCase(), (value1,value2)->value1));


坑2:NullPointerException

使用到的类

@Data
public class Person{
    private Long id;
    private String name;
    public Person(Long id, String name) {
        this.id = id;
        this.name = name;
    }
}

案例:

List<Person> list = Arrays.asList(new Person(3L, "张三"), new Person(4L, "李四"), new Person(5L, null));
Map<Long, String> dataMap = list.stream()
        .collect(Collectors.toMap(Person::getId, Person::getName, (v1, v2) -> v1));

异常:

image.png

分析:

在使用toMap时,是使用map.merge来合并数据的,而在merge时,如果value为空则跑出NPE异常。

image.png

image.png


解决方案:

// 方案一,先过滤掉空值
List<Person> list = Arrays.asList(new Person(3L, "张三"), new Person(4L, "李四"),
        new Person(5L, null));
Map<Long, String> dataMap = list.stream().filter(o -> Objects.nonNull(o.getName()))
        .collect(Collectors.toMap(Person::getId, Person::getName));

//方案二,使用Optional,在取值时不能直接使用get,optional.get()对于空值会抛NPE
List<Person> list = Arrays.asList(new Person(3L, "张三"), new Person(4L, "李四"),
        new Person(5L, null));
Map<Long, Optional<String>> dataMap = list.stream().collect(
        Collectors.toMap(Person::getId, o -> Optional.ofNullable(o.getName()))
);
System.out.println(map.get(3L).get());
System.out.println(map.get(5L).orElse(null));

//方案三,自定义collect
List<Person> list = Arrays.asList(new Person(3L, "张三"), new Person(4L, "李四"),
        new Person(5L, null));
Map<Long, String> dataMap = list.stream().collect(HashMap::new,
        (map, element) -> map.put(element.getId(), element.getName()), HashMap::putAll);



相关文章

分类

{{name}}

标签

{{name}}

相关文章

广告区域
没有相关数据