Alternative for throwingMerger in Java 8

前端 未结 1 1427
伪装坚强ぢ
伪装坚强ぢ 2020-12-03 19:34

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

相关标签:
1条回答
  • 2020-12-03 20:12

    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));
    }
    
    0 讨论(0)
提交回复
热议问题