Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would java map collector throw a duplicate key on the original object

Tags:

java

When running the following code compiled on JDK 8 the exception thrown is

java.lang.IllegalStateException: Duplicate key 1

which indicates that even though the new key is supposed to be a different object from a different type, the exception still mentions the original object.

List<Integer> ints = ImmutableList.of(1, 1);
Map<String, Integer> m = ints.stream()
    .collect(Collectors.toMap(intgr -> String.valueOf(intgr + 1), Function.identity()));

The mapping function can be arbitrarily complex and totally different objects end up being mapped to the same key, why would this exception behavior be chosen?

I mean why the exception thrown is not "Duplicate key 2"?

Note: in our case the original value that was mapped is a third party class without toString implementation so it was impossible to know what caused the duplication.

like image 933
Vic Avatar asked Jul 24 '18 08:07

Vic


People also ask

Can a map have duplicate keys in Java?

Duplicate keys are not allowed in a Map.

Which collection in Java allows duplicate keys?

You can use Multimap it supports duplicate keys but it also support duplicate keys and value pairs. Best solution for you is use Multimap and check if value already exist then dont add it.

What happens when we add duplicate key in map?

If you try to insert the duplicate key, it will replace the element of the corresponding key. HashMap is similar to HashTable, but it is unsynchronized. It allows to store the null keys as well, but there should be only one null key object and there can be any number of null values.

Does map take duplicate values?

Map does not supports duplicate keys. you can use collection as value against same key. Because if the map previously contained a mapping for the key, the old value is replaced by the specified value.


1 Answers

This could be a jdk bug. I think it may be resolved in higher version. (I'm using 1.8_162)

You can see Collectors#throwingMerger.

private static <T> BinaryOperator<T> throwingMerger() {
    return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
}

While the input parameter u, v is come from Map#merge. It is the old value and new value. So it is 1, 1 in your case. But the error message is Duplicate key, it's totally wrong because both u and v is not key but value.

EDIT

Checked jdk 10, this bug has been fixed.

See https://github.com/XDean/openjdk/blob/67672eec97164de10a9ca83ddbcef6b42816ed04/src/java.base/share/classes/java/util/stream/Collectors.java#L174

Now Collectors.toMap use its own accumulate function rather than use Map.merge.

like image 66
Dean Xu Avatar answered Nov 15 '22 00:11

Dean Xu