I'm trying to convert a list of objects to a Map using Java Streams:
List<String> list = List.of("a", "b", "a");
Map<String, Integer> map = list.stream()
.collect(Collectors.toMap(s -> s, String::length));
This throws:
java.lang.IllegalStateException: Duplicate key a (attempted merging values 1 and 1)
I expected it to just create a map with unique keys, but I forgot that my list has duplicates. What's the correct way to handle this if duplicates may occur? Is there a way to merge them, or just keep the first one?
Make sure you have 'distinct' values:
Map<String, Integer> map = list.stream()
.distinct()
.collect(Collectors.toMap(s -> s, String::length));
It throws the exception because the Collector does not know what to do with the duplicates in the merge operation. In its internal it will use:
/**
* {@code BiConsumer<Map, T>} that accumulates (key, value) pairs
* extracted from elements into the map, throwing {@code IllegalStateException}
* if duplicate keys are encountered.
*
* @param keyMapper a function that maps an element into a key
* @param valueMapper a function that maps an element into a value
* @param <T> type of elements
* @param <K> type of map keys
* @param <V> type of map values
* @return an accumulating consumer
*/
private static <T, K, V>
BiConsumer<Map<K, V>, T> uniqKeysMapAccumulator(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper) {
return (map, element) -> {
K k = keyMapper.apply(element);
V v = Objects.requireNonNull(valueMapper.apply(element));
V u = map.putIfAbsent(k, v);
if (u != null) throw duplicateKeyException(k, u, v);
};
}
Hence the exception you are seeing. To handle it you can just tell it with a merge function what to do in case of a duplicate:
Map<String, Integer> map =
list.stream()
.collect(Collectors.toMap(
s -> s,
String::length,
(a1, a2) -> a1
));
This uses the implementation from its [Java Doc](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-java.util.function.BinaryOperator-)
public static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper,
BinaryOperator<U> mergeFunction)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With