I'm implementing own collector that uses merge function. Unfortunately, for some of my cases, I can't reuse the following JDK merger function that thrown IllegalStateException.
java.util.stream.Collectors#throwingMerger
It happens due to the fact that it has private access modifier and access from other(not inner) classes is restricted. However, javadoc says the following:
This can be used to enforce the assumption that the elements being collected are distinct
But, as I see, java doc is out of date. It can't be used. The question is whether JDK provides access to similar functionality for the java developers(similar method, constant etc) or one should write it on their own?
The throwingMerger()
is implemented as follows
private static <T> BinaryOperator<T> throwingMerger() {
return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
}
You could add a similar method to your code base, but you should be aware of the fundamental problem of that merger: the exception message is incorrect. The first argument to that function is the old value, not the key. The key is not available to this function, so producing an exception message including the duplicate key is impossible for this merge function.
So, since fixing this issue at this place is impossible, it’s good that this function is an implementation detail, so it could be removed for Java 9 without any compatibility constraints.
For providing a reasonable diagnostic, toMap
without merge function needs an entirely different implementation than toMap
with (non-throwing) merge function, so the toMap
and toConcurrentMap
collectors without merge function have been entirely rewritten.
A common reason for asking for the throwing merge function, is that there is no toMap
overload accepting a map Supplier
without the merge function. But since the throwing merger is not going to do the right thing and an entirely different approach is needed when duplicate keys should be rejected, you may use the collector of this answer instead. A slightly improved version of it is
public static <T, K, V, M extends Map<K,V>> Collector<T, ?, M> toMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper,
Supplier<M> mapSupplier) {
return Collector.of(mapSupplier,
(m,t) -> putUnique(m, keyMapper.apply(t),
Objects.requireNonNull(valueMapper.apply(t))),
(m1,m2) -> {
if(m1.isEmpty()) return m2;
if(!m2.isEmpty()) 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));
}
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