【发布时间】:2015-03-24 20:31:02
【问题描述】:
Java 8 为我们提供了具有非常长签名的新方法,如下所示:
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)
我觉得奇怪的是通配符被用来确保前两个参数尽可能通用,而第三个参数只是一个BinaryOperator<U>。如果他们一直保持一致,那肯定是BiFunction<? super U,? super U,? extends U>?。我错过了什么吗?这样做有充分的理由吗,还是他们只是想避免让已经很可怕的签名变得更糟?
编辑
我了解 PECS,并且我了解 mergeFunction 应该被认为是获取两个 Us 并取回 U 的一种方式。然而,能够拥有一个可以以多种不同方式重用的对象将会很有用。例如:
static final BiFunction<Number, Number, Double>
MULTIPLY_DOUBLES = (a, b) -> a.doubleValue() * b.doubleValue();
显然这不是BinaryOperator<Double>,但可以将其视为。如果您可以将MULTIPLY_DOUBLES 用作both BiFunction<Number, Number, Double> 和BinaryOperator<Double>,那就太好了,具体取决于上下文。特别是,您可以简单地传递 MULTIPLY_DOUBLES 以表明您希望使用乘法来减少 doubles 的负载。然而,toMap(以及 Java 8 中的其他新方法)的签名不允许这种灵活性。
【问题讨论】:
-
? extends U不等于U。 -
@pbabcdefp
*Operator的原理是对相同的输入和输出参数进行操作;因此supering 参数和extendsing 返回值没有意义。 -
@robbmj 带有类型推断和您没有注意到的 IDE。还不错
-
不,你的解释是对的。如果它是更广泛的
BiFunction,这将起作用,但他们确实希望最小化签名的复杂性——更重要的是,更窄的签名使类型推断更容易工作,所以你可以只传递一个无类型的 lambda 并拥有它推断正确。 -
具有讽刺意味的是,
Map.merge其中mergeFunction最终会 接受BiFunction<? super V,? super V,? extends V>。