Reputation: 63
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?
Upvotes: 6
Views: 6353
Reputation: 298539
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.
Upvotes: 14
Reputation: 45005
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?
Upvotes: 6