How to Convert List to Map in Java – 如何在Java中把列表转换为地图

最后修改: 2018年 7月 23日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Converting List to Map is a common task. In this tutorial, we’ll cover several ways to do this.

List转换为Map是一项常见的任务。在本教程中,我们将介绍几种方法来做到这一点。

We’ll assume that each element of the List has an identifier that will be used as a key in the resulting Map.

我们将假设List中的每个元素都有一个标识符,该标识符将被用作生成的Map中的一个键。

2. Sample Data Structure

2.数据结构样本

First, we’ll model the element:

首先,我们将对元素进行建模。

public class Animal {
    private int id;
    private String name;

    //  constructor/getters/setters
}

The id field is unique, so we can make it the key.

id字段是唯一的,所以我们可以把它作为关键。

Let’s start converting with the traditional way.

让我们从传统方式开始转换。

3. Before Java 8

3.在Java 8之前

Evidently, we can convert a List to a Map using core Java methods:

显然,我们可以使用Java核心方法将List转换为Map

public Map<Integer, Animal> convertListBeforeJava8(List<Animal> list) {
    Map<Integer, Animal> map = new HashMap<>();
    for (Animal animal : list) {
        map.put(animal.getId(), animal);
    }
    return map;
}

Now we test the conversion:

现在我们测试一下转换。

@Test
public void whenConvertBeforeJava8_thenReturnMapWithTheSameElements() {
    Map<Integer, Animal> map = convertListService
      .convertListBeforeJava8(list);
    
    assertThat(
      map.values(), 
      containsInAnyOrder(list.toArray()));
}

4. With Java 8

4.使用Java 8

Starting with Java 8, we can convert a List into a Map using streams and Collectors:

从Java 8开始,我们可以使用流和CollectorsList转换成Map

 public Map<Integer, Animal> convertListAfterJava8(List<Animal> list) {
    Map<Integer, Animal> map = list.stream()
      .collect(Collectors.toMap(Animal::getId, Function.identity()));
    return map;
}

Again, let’s make sure the conversion is done correctly:

再次,让我们确保转换的正确性。

@Test
public void whenConvertAfterJava8_thenReturnMapWithTheSameElements() {
    Map<Integer, Animal> map = convertListService.convertListAfterJava8(list);
    
    assertThat(
      map.values(), 
      containsInAnyOrder(list.toArray()));
}

5. Using the Guava Library

5.使用Guava库

Besides core Java, we can use third-party libraries for the conversion.

除了核心Java,我们还可以使用第三方库进行转换。

5.1. Maven Configuration

5.1.Maven配置

First, we need to add the following dependency to our pom.xml:

首先,我们需要在我们的pom.xml中添加以下依赖关系。

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

The latest version of this library can always be found here.

这个库的最新版本总是可以在这里找到。

5.2. Conversion With Maps.uniqueIndex()

5.2.用Maps.uniqueIndex()进行转换

Second, let’s use Maps.uniqueIndex() method to convert a List into a Map:

其次,让我们使用Maps.uniqueIndex()方法来将List转换成Map

public Map<Integer, Animal> convertListWithGuava(List<Animal> list) {
    Map<Integer, Animal> map = Maps
      .uniqueIndex(list, Animal::getId);
    return map;
}

Finally, we test the conversion:

最后,我们对转换进行测试。

@Test
public void whenConvertWithGuava_thenReturnMapWithTheSameElements() {
    Map<Integer, Animal> map = convertListService
      .convertListWithGuava(list);
    
    assertThat(
      map.values(), 
      containsInAnyOrder(list.toArray()));
}

6. Using Apache Commons Library

6.使用Apache Commons Library

We can also make a conversion with the Apache Commons library method.

我们也可以用Apache Commons库的方法进行转换。

6.1. Maven Configuration

6.1.Maven配置

First, let’s include Maven dependency:

首先,让我们加入Maven的依赖性。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
</dependency>

The latest version of this dependency is available here.

该依赖关系的最新版本可在此处获得。

6.2. MapUtils

6.2.MapUtils

Second, we’ll make the conversion using MapUtils.populateMap():

其次,我们将使用MapUtils.populateMap()进行转换。

public Map<Integer, Animal> convertListWithApacheCommons2(List<Animal> list) {
    Map<Integer, Animal> map = new HashMap<>();
    MapUtils.populateMap(map, list, Animal::getId);
    return map;
}

Finally, we can make sure it works as expected:

最后,我们可以确保它按预期工作。

@Test
public void whenConvertWithApacheCommons2_thenReturnMapWithTheSameElements() {
    Map<Integer, Animal> map = convertListService
      .convertListWithApacheCommons2(list);
    
    assertThat(
      map.values(), 
      containsInAnyOrder(list.toArray()));
}

7. Conflict of Values

7.价值观的冲突

Let’s check what happens if the id field isn’t unique.

让我们看看如果id字段不是唯一的,会发生什么。

7.1. List of Animals With Duplicated Ids

7.1.List of Animals With Duplicated Ids

First, we create a List of Animals with non-unique ids:

首先,我们创建一个具有非唯一idAnimals的List

@Before
public void init() {

    this.duplicatedIdList = new ArrayList<>();

    Animal cat = new Animal(1, "Cat");
    duplicatedIdList.add(cat);
    Animal dog = new Animal(2, "Dog");
    duplicatedIdList.add(dog);
    Animal pig = new Animal(3, "Pig");
    duplicatedIdList.add(pig);
    Animal cow = new Animal(4, "Cow");
    duplicatedIdList.add(cow);
    Animal goat= new Animal(4, "Goat");
    duplicatedIdList.add(goat);
}

As shown above, the cow and the goat have the same id.

如上所示,有相同的id

7.2. Checking the Behavior

7.2.检查行为

Java Map‘s put() method is implemented so that the latest added value overwrites the previous one with the same key.

Java Mapput()方法是这样实现的:最新添加的值会覆盖具有相同键的前一个值。

For this reason, the traditional conversion and Apache Commons MapUtils.populateMap() behave in the same way:

由于这个原因,传统的转换和Apache Commons MapUtils.populateMap()的行为方式是一样的。

@Test
public void whenConvertBeforeJava8_thenReturnMapWithRewrittenElement() {

    Map<Integer, Animal> map = convertListService
      .convertListBeforeJava8(duplicatedIdList);

    assertThat(map.values(), hasSize(4));
    assertThat(map.values(), hasItem(duplicatedIdList.get(4)));
}

@Test
public void whenConvertWithApacheCommons_thenReturnMapWithRewrittenElement() {

    Map<Integer, Animal> map = convertListService
      .convertListWithApacheCommons(duplicatedIdList);

    assertThat(map.values(), hasSize(4));
    assertThat(map.values(), hasItem(duplicatedIdList.get(4)));
}

We can see that the goat overwrites the cow with the same id.

我们可以看到,山羊覆盖了具有相同id

However, Collectors.toMap() and MapUtils.populateMap() throw IllegalStateException and IllegalArgumentException respectively:

然而,Collectors.toMap()MapUtils.populateMap()分别抛出IllegalStateExceptionIllegalArgumentException

@Test(expected = IllegalStateException.class)
public void givenADupIdList_whenConvertAfterJava8_thenException() {

    convertListService.convertListAfterJava8(duplicatedIdList);
}

@Test(expected = IllegalArgumentException.class)
public void givenADupIdList_whenConvertWithGuava_thenException() {

    convertListService.convertListWithGuava(duplicatedIdList);
}

8. Conclusion

8.结论

In this quick article, we covered various ways of converting a List to a Map, giving examples with core Java as well as some popular third-party libraries.

在这篇快速文章中,我们介绍了将List转换为Map的各种方法,给出了使用核心Java以及一些流行的第三方库的例子。

As usual, the complete source code is available over on GitHub.

像往常一样,完整的源代码可以在GitHub上找到