Общий ограниченный шаблон типа ввода функции

При чтении исходного кода интерфейса Stream я нашел эту подпись метода:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

Интересно, почему тип ввода mapper равен ? super T, в то время как тип вывода ? extends R, почему бы не использовать ? extends для обоих?

Ответы

Ответ 1

Существует эмпирическое правило, которое впервые упоминалось Джошуа Блох в его Эффективная Java-книга, которая стоит PECS.

  • Производитель PE расширяет
  • CS Consumer super

Эта функция создает результат (? extends R) из полученного (? super T).

Документация java.util.Function как бы понятна:

Представляет функцию, которая принимает один аргумент и создает результат.

Ответ 2

Предположим, вы хотите сопоставить CharSequence с другим CharSequence (таким образом, T = R = CharSequence). Какие функции будут работать для вас?

Function<Object, String> fn1 = Object::toString;

Это хорошо для вас? Да, потому что он может принимать любой CharSequence (который также является Object) и преобразовывать его в String (который также является CharSequence).

Function<CharSequence, StringBuilder> fn2 = StringBuilder::new;

Это хорошо для вас? Да, потому что он может принять любой CharSequence и преобразовать его в StringBuilder (который также является CharSequence).

Function<String, String> fn3 = String::trim;

Это хорошо для вас? Нет, потому что он не может принимать никаких CharSequence, только некоторые из них.

Таким образом, вы можете видеть, что аргумент первого типа должен быть CharSequence или любой суперкласс, но второй должен быть CharSequence или любой подкласс.

Ответ 3

Из-за PECS:) - продюсер продюсера, потребительский супер

Продвижение продюсеров. Если вам нужен список для создания значений T (вы хотите прочитать Ts из списка), вам нужно объявить его с помощью ? extends T

Потребительский супер. Если вам нужен список для использования значений T (вы хотите записать Ts в список), вам нужно объявить его с помощью ? super T