1. Overview
Converting List to Map is a common task. In this tutorial, we’ll cover several ways to do this.
We’ll assume that each element of the List has an identifier which will be used as a key in the resulting Map.
2. Sample Data Structure
Firstly, let’s model the element:
public class Animal { private int id; private String name; // constructor/getters/setters }
The id field is unique, hence we can make it the key.
Let’s start converting with the traditional way.
3. Before Java 8
Evidently, we can convert a List to a Map using core Java methods:
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; }
Let’s 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
Starting with Java 8 we can convert a List into a Map using streams and Collectors:
public Map<Integer, Animal> convertListAfterJava8(List<Animal> list) { Map<Integer, Animal> map = list.stream() .collect(Collectors.toMap(Animal::getId, animal -> animal)); 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
Besides core Java, we can use 3rd party libraries for the conversion.
5.1. Maven Configuration
Firstly, we need to add the following dependency to our pom.xml:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.6.1-jre</version> </dependency>
The latest version of this library can always be found here.
5.2. Conversion With Maps.uniqueIndex()
Secondly, let’s use Maps.uniqueIndex() method to convert a List into a Map:
public Map<Integer, Animal> convertListWithGuava(List<Animal> list) { Map<Integer, Animal> map = Maps .uniqueIndex(list, Animal::getId); return map; }
Finally, let’s 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
We can also make a conversion with the method of Apache Commons library.
6.1. Maven Configuration
Firstly, let’s include Maven dependency:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.2</version> </dependency>
The latest version of this dependency is available here.
6.2. MapUtils
Secondly, we’ll make the conversion using MapUtils.populateMap():
public Map<Integer, Animal> convertListWithApacheCommons2(List<Animal> list) { Map<Integer, Animal> map = new HashMap<>(); MapUtils.populateMap(map, list, Animal::getId); return map; }
Lastly, let’s 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
Let’s check what happens if the id field isn’t unique.
7.1. List of Animals With Duplicated ids
Firstly, let’s create a List of Animals with non-unique 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); }
As shown above, the cow and the goat have the same id.
7.2. Checking the Behavior
Java Map‘s put() method is implemented so that the latest added value overwrites the previous one with the same key.
For this reason, the traditional conversion and Apache Commons MapUtils.populateMap() behave in the same way:
@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))); }
As can be seen, the goat overwrites the cow with the same id.
Unlike that, 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. Conclusion
In this quick article, we’ve covered various ways of converting a List to a Map, giving examples with core Java as well as some popular third-party libraries.
As usual, the complete source code is available over on GitHub.