Java 8 List 转 Map

这篇文章属于 Java 8 教程(LTS)系列教程,点击阅读更多相关文章。

本文介绍从 Java 8 开始,如何把一个 List 转换为 Map,以及如果出现了冲突的 key 该如何处理。

准备:Dog.java

package com.wdbyte.demo;

public class Dog {
    private String name;
    private Integer age;

    public Dog() {
    }

    public Dog(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    // 省略 get set toString
}

1. Collectors.toMap

ListMap 可以使用 Java 8 中的 Collectors.toMap 进行转换。

示例1:把包含不同品种的狗类集合转换成 key 为狗的品种,value 为狗的年龄的 Map

package com.wdbyte.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ListToMap {

    public static void main(String[] args) {
        List<Dog> list = new ArrayList<>();
        list.add(new Dog("牧羊犬", 1));
        list.add(new Dog("哈士奇", 2));
        list.add(new Dog("田园犬", 3));

        // to map,key dog name,value ,dog age
        Map<String, Integer> dogMap = list.stream()
            .collect(Collectors.toMap(Dog::getName, Dog::getAge));

        System.out.println(dogMap);
    }
}

输出结果:

{牧羊犬=1, 哈士奇=2, 田园犬=3}

示例2:把包含不同品种的狗类集合转换成 key 为狗的品种,value 为狗的信息对象Map

List<Dog> list = new ArrayList<>();
list.add(new Dog("牧羊犬", 1));
list.add(new Dog("哈士奇", 2));
list.add(new Dog("田园犬", 3));

// to map,key dog name,value ,dog age
Map<String, Dog> dogMap = list.stream()
    .collect(Collectors.toMap(Dog::getName, dog -> dog));

System.out.println(dogMap);

输出结果:

{牧羊犬=Dog{, name='牧羊犬', age=1}, 哈士奇=Dog{, name='哈士奇', age=2}, 田园犬=Dog{, name='田园犬', age=3}}

2. List 转 Map,冲突 Key

还是上面的例子,如果有重复的 key 将会抛出异常。

示例1ListMap 使用 Collectors.toMap 进行转换时,如果有 key 冲突。

package com.wdbyte.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ListToMapDuplicateKey {

    public static void main(String[] args) {
        List<Dog> list = new ArrayList<>();
        list.add(new Dog("牧羊犬", 1));
        list.add(new Dog("牧羊犬", 2));
        list.add(new Dog("哈士奇", 2));
        list.add(new Dog("田园犬", 3));

        // to map,key dog name,value ,dog age
        Map<String, Integer> dogMap = list.stream()
            .collect(Collectors.toMap(Dog::getName, Dog::getAge));

        System.out.println(dogMap);
    }
}

输出结果:在遇到重复 key 时,抛出了异常。

Exception in thread "main" java.lang.IllegalStateException: Duplicate key 牧羊犬 (attempted merging values 1 and 2)
	at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:133)
	at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:180)
	at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
	...
	

示例2:传入第三个参数,当Key 冲突时,选择使用新值

List<Dog> list = new ArrayList<>();
list.add(new Dog("牧羊犬", 1));
list.add(new Dog("牧羊犬", 2));
list.add(new Dog("哈士奇", 2));
list.add(new Dog("田园犬", 3));

// to map,key dog name,value ,dog age
Map<String, Integer> dogMap = list.stream()
    .collect(Collectors.toMap(Dog::getName, Dog::getAge, (oldData, newData) -> newData));

System.out.println(dogMap);

通过 (oldData, newData) -> newData) 来选择使用新值还是老值。

输出结果:

{牧羊犬=2, 田园犬=3, 哈士奇=2}

3. List 转 Map,指定 Map 类型

示例:传入第四个参数,指定 Map 类型。

public static void main(String[] args) {
     List<Dog> list = new ArrayList<>();
     list.add(new Dog("牧羊犬", 1));
     list.add(new Dog("牧羊犬", 2));
     list.add(new Dog("哈士奇", 2));
     list.add(new Dog("田园犬", 3));

     // to map,key dog name,value ,dog age
     Map<String, Integer> dogMap = list.stream()
         .collect(Collectors.toMap(Dog::getName, Dog::getAge, 
                                   (oldData, newData) -> newData,
                                   ConcurrentHashMap::new));
     System.out.println(dogMap.getClass());
 }

输出结果:

class java.util.concurrent.ConcurrentHashMap

参考