Общий ограниченный шаблон типа ввода функции
При чтении исходного кода интерфейса 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