Mastering Java Stream toMap: Handling Duplicate Keys and Null Values
This article explains how to convert a list of Java objects into a Map using Stream's toMap collector, addresses duplicate key exceptions, demonstrates providing a merge function, handling null values with Optional, and compares alternative approaches such as manual loops, offering complete code examples.
In JDK 8, Java introduced the Stream API, which has become essential for daily development.
When you need to collect a stream into a collection, you may use collect(Collectors.toList()) or collect(Collectors.toSet()). However, converting a list of objects to a Map with toMap() can cause problems when keys are duplicated.
Consider a User class with id and name. If you read a list of User objects from a database and try to build a map where the key is id and the value is name, the following code will throw an IllegalStateException because the key 1 appears twice.
@Data
@AllArgsConstructor
public class User {
private int id;
private String name;
} public class UserTest {
@Test
public void demo() {
List<User> userList = new ArrayList<>();
// mock data
userList.add(new User(1, "Alex"));
userList.add(new User(1, "Beth"));
Map<Integer, String> map = userList.stream()
.collect(Collectors.toMap(User::getId, User::getName));
System.out.println(map);
}
}The duplicate key causes the exception. One simple fix is to provide a merge function as the third argument of Collectors.toMap, which decides how to handle conflicts.
Map<Integer, String> map = userList.stream()
.collect(Collectors.toMap(User::getId,
User::getName,
(oldData, newData) -> newData));If the value may be null, you can combine Optional to supply a default value:
Map<Integer, String> map = userList.stream()
.collect(Collectors.toMap(User::getId,
it -> Optional.ofNullable(it.getName()).orElse(""),
(oldData, newData) -> newData));Alternatively, you can fall back to a classic loop:
Map<Integer, String> map = new HashMap<>();
userList.forEach(it -> map.put(it.getId(), it.getName()));These approaches eliminate the duplicate‑key exception and handle null values gracefully, allowing you to choose between a functional Stream style or an imperative loop based on your preference.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
