Java 8
Programming
Data Structures
Map
List

Java 8 List<V> into Map<K, V>

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

In Java 8, the standard way to turn a List<V> into a Map<K, V> is Collectors.toMap. The actual design question is not "can this be done," but "which property becomes the key, what becomes the value, and what should happen when two items produce the same key."

That last point matters because the default collector throws an exception on duplicate keys. A reliable solution has to make that behavior explicit.

The Basic toMap Pattern

If you have a list of objects and want to key them by one property, stream the list and collect it into a map:

java
1import java.util.List;
2import java.util.Map;
3import java.util.function.Function;
4import java.util.stream.Collectors;
5
6class Person {
7    private final int id;
8    private final String name;
9
10    Person(int id, String name) {
11        this.id = id;
12        this.name = name;
13    }
14
15    public int getId() {
16        return id;
17    }
18
19    public String getName() {
20        return name;
21    }
22}
23
24public class Main {
25    public static void main(String[] args) {
26        List<Person> people = List.of(
27            new Person(1, "Alice"),
28            new Person(2, "Bob"),
29            new Person(3, "Cara")
30        );
31
32        Map<Integer, Person> byId = people.stream()
33            .collect(Collectors.toMap(Person::getId, Function.identity()));
34
35        System.out.println(byId.get(2).getName());
36    }
37}

Function.identity() means "store the original list element as the value." This is the cleanest form when the entire object is still useful after lookup.

Mapping to a Different Value Type

You do not have to keep the whole object. Sometimes the value should be just one field:

java
Map<Integer, String> namesById = people.stream()
    .collect(Collectors.toMap(Person::getId, Person::getName));

This reduces memory use and keeps downstream code focused. If the map only needs names, storing full Person objects is unnecessary.

The key lesson is that toMap takes two mapping functions:

  • one for the key
  • one for the value

Choose both deliberately.

Handle Duplicate Keys Explicitly

This is where many examples stop too early. If two elements produce the same key, Collectors.toMap throws IllegalStateException unless you provide a merge rule.

java
1Map<Integer, Person> byId = people.stream()
2    .collect(Collectors.toMap(
3        Person::getId,
4        Function.identity(),
5        (existing, replacement) -> existing
6    ));

That merge function keeps the first value and discards later duplicates. You could just as easily keep the replacement:

java
(existing, replacement) -> replacement

Or combine information if that matches the business rule. The important thing is to make the behavior intentional rather than discovering duplicate-key failures in production.

Preserve Order When Needed

The default map returned by toMap is not guaranteed to preserve insertion order. If order matters, supply a specific map implementation such as LinkedHashMap.

java
1import java.util.LinkedHashMap;
2
3Map<Integer, Person> orderedById = people.stream()
4    .collect(Collectors.toMap(
5        Person::getId,
6        Function.identity(),
7        (existing, replacement) -> existing,
8        LinkedHashMap::new
9    ));

This is helpful when the resulting map will later be iterated for display or exported in the same order as the input list.

When groupingBy Is the Better Tool

Sometimes duplicate keys are not errors at all. They are part of the model. In that case, groupingBy is often clearer than forcing toMap to collapse multiple values.

java
1import java.util.List;
2import java.util.Map;
3import java.util.stream.Collectors;
4
5Map<Integer, List<Person>> grouped = people.stream()
6    .collect(Collectors.groupingBy(Person::getId));

If one key naturally maps to multiple values, returning Map<K, List<V>> communicates the truth of the data better than silently discarding records.

A Loop Is Still Fine

Streams are elegant here, but a loop is not wrong. If the merge logic is complicated or needs detailed logging, a normal loop can be clearer:

java
1import java.util.HashMap;
2import java.util.Map;
3
4Map<Integer, Person> byId = new HashMap<>();
5for (Person person : people) {
6    byId.putIfAbsent(person.getId(), person);
7}

Java 8 streams are useful, not mandatory. Prefer whichever version makes the duplicate-key behavior obvious to the next person reading the code.

Common Pitfalls

The biggest mistake is forgetting about duplicate keys and being surprised by IllegalStateException. If duplicates are possible, always decide how to merge or group them.

Another common issue is using Function.identity() when the value side really only needs one property. That can create a larger object graph than necessary.

Developers also assume the resulting map preserves list order. It may not unless you provide a map supplier such as LinkedHashMap::new.

Finally, do not force toMap when the data naturally has one-to-many relationships. In those cases, groupingBy is more honest and easier to maintain.

Summary

  • Use Collectors.toMap to convert a Java 8 list into a map.
  • Choose the key mapper and value mapper based on how the map will be used.
  • Provide a merge function when duplicate keys can occur.
  • Supply a map implementation if iteration order matters.
  • Use groupingBy instead of toMap when one key legitimately maps to multiple values.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.