2017-07-19 69 views
2

我正在实现自己的收集器,它使用合并函数。不幸的是,对于我的一些情况,我无法重用抛出以下JDK合并函数IllegalStateExceptionJava中throwingMerger的替代方案8

java.util.stream.Collectors#throwingMerger 

它发生由于它具有私人访问修饰符和其他(非内部)类的访问受到限制。 然而,javadoc中说以下内容:

这可以被用来执行的假设,收集要素是不同的

但是,正如我看到,Java文档是过时的。它不能使用。问题是JDK是否为java开发人员提供了类似的功能(类似的方法,常量等),还是应该自己编写它?异常消息是不正确:

+0

这并不是真的那么难写自己。我已经写了几十次(尽管我宁愿我没有,但那是另一回事)。 –

+6

'(a,b) - > {throw new IllegalStateException(); }'有整个合并函数。 –

+3

javadoc没有过期。它正确地声明该方法可以被其他类的方法用于描述的目的。如果您查看[* generated * javadoc](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#method.summary),而不是源代码,则您你会发现这个方法甚至不存在。 javadoc不适用于您,但适用于JDK开发人员。 – Andreas

回答

3

throwingMerger()如下

private static <T> BinaryOperator<T> throwingMerger() { 
    return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }; 
} 

你可以添加一个类似的方法来你的代码库,但你应该知道,合并的根本问题的实施。该函数的第一个参数是旧值,而不是关键。此功能无法使用该密钥,因此无法为此合并功能生成包含重复密钥的异常消息。

因此,由于在这个地方解决这个问题是不可能的,所以这个函数是一个实现细节是很好的,所以它可以在没有任何兼容性限制的情况下被移除。

为了提供一个合理的诊断,而不toMap合并功能需要一个完全不同的实施比toMap用(非抛)合并功能,所以toMaptoConcurrentMap收集器没有合并功能已被完全重写。

请求投掷合并功能的常见原因是没有toMap超载接受没有合并功能的地图Supplier。但由于投掷合并不会做正确的事情,当重复的键应该被拒绝时需要完全不同的方法,您可以使用this answer的收集器来代替。它的一个稍微改进的版本是

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

谢谢!这个答案提供了我所期望的更多信息。 – dvelopp

+0

@Holger,你再次袭击......美丽!我甚至没有问过...... thx – Eugene