I have this code to get map:
List<MyObject> myList = myMethod.getList();
myList.stream().collect(
Collectors.toMap(
MyObject::getKey,
MyObject::getValue,
(e1, e2) -> {
System.out.println("Duplicate keys !!!");
return e1;
},
LinkedHashMap::new
)
);
how i can print message "Duplicate keys" with duplicate key?
HashMap stores key, value pairs and it does not allow duplicate keys. If the key is duplicate then the old key is replaced with the new value.
lang. IllegalStateException exception. To deal with the duplicate key introduce the mergeFunction as another argument. mergeFunction will resolve the duplicate key issue.
You can use a TreeMap with a custom Comparator in order to treat each key as unequal to the others. It would also preserve the insertion order in your map, just like a LinkedHashMap. So, the net result would be like a LinkedHashMap which allows duplicate keys!
A TreeMap cannot contain duplicate keys. TreeMap cannot contain the null key. However, It can have null values.
As explained in this answer, this is a known issue that is going to be fixed in Java 9—at least for the toMap
collector that doesn’t accept a merge function.
Since the merge function only receives the two values to be merged and signature can’t be easily changed, there is no fix for these overloaded methods in sight. Unfortunately, there is no toMap
collector which accepts a Map
Supplier
without an explicit merge function, so unless this will change until the release, there will be no fix for your scenario where a LinkedHashMap
should be returned.
So the solution is to implement your own collector. Then, you don’t have to wait for Java 9 and don’t risk to get disappointed.
static <T, K, V, M extends Map<K, V>> Collector<T, ?, M> toMap(
Function<T, K> keyExtractor, Function<T, V> valueExtractor, Supplier<M> mapSupplier) {
return Collector.of(mapSupplier,
(m, t) -> putUnique(m, keyExtractor.apply(t), valueExtractor.apply(t)),
(m1,m2)-> { m2.forEach((k, v) -> putUnique(m1, k, v)); return m1; }
);
}
private static <K,V> void putUnique(Map<K,V> map, K key, V v1){
V v2 = map.putIfAbsent(key, v1);
if(v2 != null) throw new IllegalStateException(
String.format("Duplicate key %s (values %s and %s)", key, v1, v2));
}
You can use this collector as
LinkedHashMap<KeyType, ValueType> map = myList.stream()
.collect(toMap(MyObject::getKey, MyObject::getValue, LinkedHashMap::new));
or use a qualified MyCollector.toMap
, referring to the class where you put that custom collector.
how i can print message "Duplicate keys" with duplicate key?
With your current code, you will get the message "Duplicate keys" with a list of MyObject
which contains at least 2 instances of MyObject
that have equal objects as value for getKey()
, for example Arrays.asList(new MyObject("foo", "bar"), new MyObject("foo", "bar2"))
.
How to get the corresponding key?
Up to now it is not possible to get the corresponding key, what you currently get from the merge function are actually 2 values mapped with the same key that need to be merged to keep only one value for the corresponding key.
Your problem is a known issue that is fixed in Java 9 see JDK-8040892 for more details, the corresponding fix will allow us to get from the merge function both the key and the values to merge.
See Also Why does Collectors.toMap report value instead of key on Duplicate Key error?
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