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

Vic :

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.

Dean Xu :

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.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=68562&siteId=1