Как конвертировать список в карту в Java

Как конвертировать список в карту в Java

1. обзор

ПреобразованиеList вMap - обычная задача. В этом руководстве мы рассмотрим несколько способов сделать это.

Предположим, что каждый элементList имеет идентификатор, который будет использоваться в качестве ключа в результирующемMap.

2. Пример структуры данных

Во-первых, давайте смоделируем элемент:

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

    //  constructor/getters/setters
}

Полеid уникально, поэтому мы можем сделать его ключевым.

Давайте начнем преобразовывать традиционным способом.

3. До Java 8

Очевидно, мы можем преобразоватьList в ожидающие основные методы JavaMap :

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

Давайте проверим конверсию:

@Test
public void whenConvertBeforeJava8_thenReturnMapWithTheSameElements() {
    Map map = convertListService
      .convertListBeforeJava8(list);

    assertThat(
      map.values(),
      containsInAnyOrder(list.toArray()));
}

4. С Java 8

Начиная с Java 8, мы можем преобразоватьList вMap, используя потоки иCollectors:

 public Map convertListAfterJava8(List list) {
    Map map = list.stream()
      .collect(Collectors.toMap(Animal::getId, animal -> animal));
    return map;
}

Опять же, давайте убедимся, что преобразование выполнено правильно:

@Test
public void whenConvertAfterJava8_thenReturnMapWithTheSameElements() {
    Map map = convertListService.convertListAfterJava8(list);

    assertThat(
      map.values(),
      containsInAnyOrder(list.toArray()));
}

5. Использование библиотеки Guava

Помимо ядра Java, мы можем использовать сторонние библиотеки для преобразования.

5.1. Конфигурация Maven

Во-первых, нам нужно добавить следующую зависимость к нашемуpom.xml:


    com.google.guava
    guava
    23.6.1-jre

Последнюю версию этой библиотеки всегда можно найтиhere.

5.2. Конверсия сMaps.uniqueIndex()

Во-вторых, давайте воспользуемся методомMaps.uniqueIndex() для преобразованияList вMap:

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

Наконец, давайте проверим конверсию:

@Test
public void whenConvertWithGuava_thenReturnMapWithTheSameElements() {
    Map map = convertListService
      .convertListWithGuava(list);

    assertThat(
      map.values(),
      containsInAnyOrder(list.toArray()));
}

6. Использование библиотеки Apache Commons

Мы также можем выполнить преобразование с помощью метода  библиотеки Apache Commons.

6.1. Конфигурация Maven

Во-первых, давайте включим зависимость Maven:


    org.apache.commons
    commons-collections4
    4.2

Последняя версия этой зависимости доступнаhere.

6.2. MapUtilsс

Во-вторых, мы сделаем преобразование, используяMapUtils.populateMap():

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

Наконец, давайте убедимся, что все работает должным образом:

@Test
public void whenConvertWithApacheCommons2_thenReturnMapWithTheSameElements() {
    Map map = convertListService
      .convertListWithApacheCommons2(list);

    assertThat(
      map.values(),
      containsInAnyOrder(list.toArray()));
}

7. Конфликт ценностей

Давайте посмотрим, что произойдет, если полеid не уникальное.

7.1. List изAnimals с дублированнымids

Во-первых, давайте создадимList изAnimals с неуникальнымids:

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

Как показано выше,cow иgoat имеют одинаковыеid.

7.2. Проверка поведения

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

По этой причине традиционное преобразование и Apache CommonsMapUtils.populateMap() ведут себя одинаково:

@Test
public void whenConvertBeforeJava8_thenReturnMapWithRewrittenElement() {

    Map map = convertListService
      .convertListBeforeJava8(duplicatedIdList);

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

@Test
public void whenConvertWithApacheCommons_thenReturnMapWithRewrittenElement() {

    Map map = convertListService
      .convertListWithApacheCommons(duplicatedIdList);

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

Как видно,goat заменяетcow тем жеid.

В отличие от этого,Collectors.toMap() and MapUtils.populateMap() throw IllegalStateException and IllegalArgumentException respectively:

@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. Заключение

В этой быстрой статье мы рассмотрели различные способы преобразованияList вMap, , например с использованием ядра Java, а также некоторых популярных сторонних библиотек.

Как обычно, доступен полный исходный кодover on GitHub.