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>?. Я что-то упускаю? Есть ли веская причина для этого, или они просто хотят избежать еще более ужасной подписи?
Edit
Я понимаю PECS, и я понимаю принцип, что mergeFunction следует рассматривать как способ взять два U и вернуть a U. Однако было бы полезно иметь объект, который можно было бы повторно использовать разными способами. Например:
static final BiFunction<Number, Number, Double>
MULTIPLY_DOUBLES = (a, b) -> a.doubleValue() * b.doubleValue();
Очевидно, что это не BinaryOperator<Double>, но его можно рассматривать как единое целое. Было бы здорово, если бы вы использовали MULTIPLY_DOUBLES как a BiFunction<Number, Number, Double>, так и BinaryOperator<Double>, в зависимости от контекста. В частности, вы можете просто передать MULTIPLY_DOUBLES, чтобы указать, что вы хотите уменьшить нагрузку double с помощью умножения. Однако подпись для toMap (и других новых методов в Java 8) не допускает такой гибкости.