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
Mapwith
toMap()can cause problems when keys are duplicated.
Consider a
Userclass with
idand
name. If you read a list of
Userobjects from a database and try to build a map where the key is
idand the value is
name, the following code will throw an
IllegalStateExceptionbecause the key
1appears twice.
<code>@Data
@AllArgsConstructor
public class User {
private int id;
private String name;
}
</code> <code>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);
}
}
</code>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.
<code>Map<Integer, String> map = userList.stream()
.collect(Collectors.toMap(User::getId,
User::getName,
(oldData, newData) -> newData));
</code>If the value may be
null, you can combine
Optionalto supply a default value:
<code>Map<Integer, String> map = userList.stream()
.collect(Collectors.toMap(User::getId,
it -> Optional.ofNullable(it.getName()).orElse(""),
(oldData, newData) -> newData));
</code>Alternatively, you can fall back to a classic loop:
<code>Map<Integer, String> map = new HashMap<>();
userList.forEach(it -> map.put(it.getId(), it.getName()));
</code>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.
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.