Java 8中throwMerger的替代方案

我正在实现使用合并function的自己的收集器。 不幸的是,对于我的一些情况,我不能重用抛出IllegalStateException的以下JDK合并函数。

java.util.stream.Collectors#throwingMerger 

它发生的原因是它具有私有访问修饰符,并且来自其他(非内部)类的访问受到限制。 但是,javadoc说:

这可用于强制假设所收集的元素是不同的

但是,正如我所见,java doc已经过时了。 它不能使用。 问题是JDK是否为java开发人员提供了类似function的访问权限(类似方法,常量等),还是应该自己编写?

throwingMerger()实现如下

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

您可以在代码库中添加类似的方法,但是您应该知道该合并的基本问题:exception消息不正确。 该函数的第一个参数是旧值,而不是键。 密钥不可用于此函数,因此生成包含重复键的exception消息对于此合并function是不可能的。

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

为了提供合理的诊断,没有合并函数的toMap需要一个完全不同于带有(非抛出)合并函数的toMap ,因此没有合并函数的toMaptoConcurrentMap收集器已被完全重写。

要求抛出合并function的一个常见原因是没有toMap过载接受没有合并function的地图Supplier 。 但是,由于投掷合并不会做正确的事情,并且当重复键被拒绝时需要完全不同的方法,您可以使用此答案的收集器。 它的略有改进版本

 public static > Collector toMap( Function keyMapper, Function valueMapper, Supplier 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  void putUnique(Map 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)); }