Course contents

Collectors.toMap and working with maps

Collectors.toMap overloads, duplicate keys, null values, map suppliers, concurrent maps and entrySet stream transformations.

PremiumMust know for interviewsLesson12 min readCoreReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: labels, collisions and the output box
  2. toMap under the hood: the overloads you actually use
  3. Advanced: map suppliers, null values and concurrent maps
  4. Working with existing maps using streams
  5. When groupingBy is the better choice
  6. How to say it in the interview

🗺️ What is

Collectors.toMap? Collectors.toMap is the stream collector that turns elements into map entries by asking for a key and a value. It acts like a labeling machine at the end of a conveyor belt: each item gets a label, then Java puts the labeled value into a map. For example, a stream of users can become Map<String, User> keyed by user id.

For this lesson, we'll focus on the stream side of map work: the toMap overloads, duplicate-key policies, null-value traps, ordered and sorted suppliers, toConcurrentMap, and transformations that start from map.entrySet().stream(). We will link to Everyday Map operations for loop-based Map methods, and to Collectors deep dive for the general Collector API.

Below the line (out of scope)

The 30-second answer

Use Collectors.toMap(keyMapper, valueMapper) only when keys are unique and values are non-null. If two elements produce the same key, it throws IllegalStateException, in Java 21 with a message like Duplicate key u1 (attempted merging values Mina and Mira). Add the three-argument overload when duplicates are possible, for example Integer::sum, (first, second) -> first or (first, second) -> second. Add the four-argument overload when map type matters, such as LinkedHashMap::new to preserve encounter order or TreeMap::new to sort keys. Function.identity() means the whole stream element is the value. toMap rejects null values because it uses merge-style accumulation, so use a custom three-argument collect when you truly need nulls. If one key maps to many values, stop fighting toMap and use groupingBy.

What you’ll learn

  • Choose the right **Collectors.toMap overload** for duplicate keys, order and sorted output
  • Explain why the two-argument toMap throws IllegalStateException on duplicate keys
  • Handle null values safely when toMap delegates to Map.merge
  • Use Function.identity(), LinkedHashMap::new, TreeMap::new and toConcurrentMap deliberately
  • Stream over map.entrySet() to filter, sort, invert and transform maps
  • Recognize when **groupingBy** is the better collector than forcing a map merge

01Picture it first: labels, collisions and the output box

Picture a belt of user records. The key mapper prints the label on the box, the value mapper decides what goes inside, and the merge function is the tie-breaker when two boxes get the same label. The map supplier chooses the shelf: unordered HashMap, insertion-ordered LinkedHashMap, sorted TreeMap, or a concurrent map.

Fig. 1

A stream flows through key and value mappers into a map; duplicate keys go through a merge function and the supplier chooses HashMap, LinkedHashMap or TreeMap

A stream flows through key and value mappers into a map; duplicate keys go through a merge function and the supplier chooses HashMap, LinkedHashMap or TreeMap

Notice the two decisions that candidates often blend together. Duplicate policy is not the same as map type. You can sum duplicate values into a HashMap, keep the last value in a LinkedHashMap, or reject duplicates in a TreeMap.

02toMap under the hood: the overloads you actually use

Try it yourself first

Before reading on, predict the exception from the first collector. Then decide which duplicate policy you want: fail, keep first, keep last, or combine.

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

record User(String id, String name) { }

public class ToMapDuplicateDemo {
    public static void main(String[] args) {
        List<User> users = List.of(
                new User("u1", "Mina"),
                new User("u2", "Ravi"),
                new User("u1", "Mira")
        );

        try {
            users.stream().collect(Collectors.toMap(User::id, User::name));
        } catch (IllegalStateException duplicate) {
            System.out.println(duplicate.getMessage());
            // Duplicate key u1 (attempted merging values Mina and Mira)
        }

        Map<String, User> firstUserById = users.stream().collect(
                Collectors.toMap(
                        User::id,
                        Function.identity(),
                        (first, second) -> first
                )
        );

        System.out.println(firstUserById.get("u1").name()); // Mina
    }
}

Premium lesson

Keep reading with the Java Pass

The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

  • Advanced: map suppliers, null values and concurrent maps
  • Working with existing maps using streams
  • When groupingBy is the better choice
  • How to say it in the interview

From ₹199 · one-time payment · No auto-renewal

Practise this topicCollectors: interview questions & scenarios
Further reading (5)