static <T,K,U,M extends Map<K,U>> Collector<T,?,M> toMap( Function<? super T,? extends K> keyMapper,Function<? super T,? extends U> valueMapper,BinaryOperator<U> mergeFunction,Supplier<M> mapSupplier)
我觉得奇怪的是,通配符已被用于确保前两个参数尽可能的一般,但第三个参数只是一个二进制操作符U.如果他们一致,肯定会是一个BiFunction超级U超级U延伸U>.我错过了什么吗?这是否有很好的理由,还是只是想避免使已经可怕的签名变得更糟?
编辑
我理解PECS,我理解合并函数应该被认为是一种采用两个Us并返回一个U的方式的原则.但是,能够有一个可以以许多不同的方式重用的对象将是有用的.例如:
static final BiFunction<Number,Number,Double> MULTIPLY_DOUBLES = (a,b) -> a.doubleValue() * b.doubleValue();
显然这不是BinaryOperator< Double>但是它可以被视为一个.如果您可以使用MULTIPLY_DOUBLES作为BiFunction< Number,Double>和BinaryOperator< Double>,取决于上下文.特别地,您可以简单地传递MULTIPLY_DOUBLES来表明您希望使用乘法减少加倍的倍数.然而,toMap(和Java 8中的其他新方法)的签名不允许这种灵活性.
解决方法
这不仅可以通过以下事实来说明:toMap收集器的mergeFunction最终将在Map.merge
处接受BiFunction<?超级V超级V延伸V>您也可以将这样的BiFunction转换为所需的BinaryOperator:
BiFunction<Number,Double> MULTIPLY_DOUBLES = (a,b) -> a.doubleValue() * b.doubleValue(); Stream<Double> s = Stream.of(42.0,0.815); Optional<Double> n=s.reduce(MULTIPLY_DOUBLES::apply);
或完全通用:
public static <T> Optional<T> reduce( Stream<T> s,BiFunction<? super T,? super T,? extends T> f) { return s.reduce(f::apply); }
创建BinaryOperator和UnaryOperator的最有可能的原因是与这些没有这样的超级接口的这些函数的原始类型版本对称.
在这方面,方法是一致的
Stream.reduce(BinaryOperator< T)
> IntStream.reduce(IntBinaryOperator)
> DoubleStream.reduce(DoubleBinaryOperator)
> LongStream.reduce(LongBinaryOperator)
要么
> Arrays.parallelPrefix(T [] array,BinaryOperator< T> op)> Arrays.parallelPrefix(int [] array,IntBinaryOperator op)> Arrays.parallelPrefix(double [] array,DoubleBinaryOperator op)> Arrays.parallelPrefix(long [] array,LongBinaryOperator op)