#java #generics #lambda #java_stream
Есть функция:Stream map(Function mapper); Она производит операции над элементами Stream и возвращает Stream с результирующими элементами. На вход мы подаем реализацию функционального интерфейса, то есть метода: R apply(T t); Я это и делаю: .map(User::getName) То есть, если я правильно понимаю, вместо T "подставляется" тип User, вместо R тип String. Тогда объясните , для чего вообще нужно super и extends в параметрах? Я понимаю, что super T означает: "T или любой его суперкласс", extends R означает "R или любой его подкласс"? В чем преимущество T по сравнению с super T, где это можно использовать? С обычным методом все понятно (можем передать экземпляр любого суперкласса как параметр), а вот с параметром типа функционального интерфейса не очень. Мы ведь просто передаем реализацию с конкретными T(User) и R(String), где нам тогда могут пригодится подклассы и суперклассы?
Ответы
Ответ 1
Java generics построены на идеи PECS (production - extends; consumer - super), т.е. производитель определяет верхние границы, а потребитель определяет нижние границы. Потом в Function где T - входные данные, а R - выходные данные. Его часто называют отображением, так как входные данные "отображаются" в выходные. Рассмотрим пример: Functionfun = (str) -> Integer.parseInt(str); System.out.println(fun.apply("234")); Здесь входной должна быть строчкой, а в выходе мы получим Integer. Получается в вашем варианте входной был User, а выходе мы должны получить имя юзера. Ответ 2
Как раз таки наоборот, преимущество типа ? super T по сравнению с T состоит в том, что в первом случае на вход функции можно посылать объекты разных типов, которые либо T либо являются суперкласом T. То есть мы не можем сказать, что тип параметра T. А также, мы не можем посылать объекты наследники T, в качестве параметра функции. Во втором случае тип T определен однозначно по иерархии, несмотря на то, что он является обобщенным типом, не принимаются наследники T и он не является наследником T.
Комментариев нет:
Отправить комментарий