Главная страница
Навигация по странице:

  • 17) Любую ли лямбду можно заменить на анонимный класс

  • Почему пример из части про императивность на самом деле с примесью декларативности

  • 20) Что такое default методы в интерфейсе и для чего они были введены

  • До Java 8 все методы в интерфейсах были абстрактными. К чему это вело

  • 21) К каким переменным есть доступ из лямбда-выражения

  • 22) Любой анонимный класс можно заменить на лямбду

  • 25) Что такое ленивая инициализация стрима

  • 26) Две терминальные операции в одном выражении

  • 27) Что такое терминальная операция

  • 28) Что возвращают промежуточные операции над стримом

  • 29) Для чего нужны параллельные стримы

  • 31) Что такое [ФИ [функциональный интерфейс и для чего он нужен и зачем были добавлены

  • 32) Какой аннотацией помечается функциональный интерфейс

  • 34) Где находятся функциональные интерфейсы

  • 36) [ФИ Функциональные интерфейсы что они принимают и что возвращают

  • 37) Какие есть способы [инстацировать функциональные интерфейсы (анонимный класс, лямбда выражения, ссылки на методы)

  • билеты модуль 7. 1 Функциональные интерфейсы, основные типы


    Скачать 184 Kb.
    Название1 Функциональные интерфейсы, основные типы
    Дата05.12.2022
    Размер184 Kb.
    Формат файлаdoc
    Имя файлабилеты модуль 7.doc
    ТипДокументы
    #828359
    страница2 из 4
    1   2   3   4

    16) Что такое стримы? Для чего они нужны? Когда их лучше использовать?

    Стримы избавляют программистов от написания стереотипного кода всякий раз, когда нужно сделать что-то с набором элементов. То есть благодаря стримам не приходится думать о деталях реализации.
    Есть и другие [плюсы:
    Стримы поддерживают один из основных принципов хорошего проектирования — слабую связанность (low coupling).

    Чем меньше класс знает про другие классы — тем лучше. Алгоритму сортировки не должно быть важно, ч

    то конкретно он сортирует. Это и делают стримы.

    С помощью стримов операции с коллекциями проще распараллелить: в императивном подходе для этого бы понадобился

    минимум ещё один цикл.

    Стримы позволяют уменьшить число побочных эффектов: методы Stream API не меняют исходные коллекции.

    Со Stream API лаконично записываются сложные алгоритмы обработки данных.
    Stream API любит неизменяемые данные. Если вы хотите поменять существующие структуры данных, а не создать новые, вам нужно что-то другое.

    Посмотрите в сторону новых стандартных методов (например, List.replaceAll).
    Stream API [любит независимые данные. Если для получения результата вам нужно использовать одновременно несколько элементов

    из входного набора, без сторонних библиотек будет очень коряво. Но библиотеки вроде StreamEx часто решают эту проблему.
    Stream API любит решать одну задачу за проход. Если вы хотите в один обход данных решить несколько разных задач,

    готовьтесь писать свои коллекторы. И не факт, что это вообще получится.
    Stream API не любит проверяемые исключения. Вам будет не очень удобно кидать их из операций Stream API.

    Опять же есть библиотеки, которые пытаются это облегчить (скажем, jOOλ), но я бы рекомендовал отказываться от проверяемых исключений.
    В стандартном Stream API не хватает некоторых операций, которые очень нужны. Например, takeWhile, появится только в Java 9. Может оказаться, что вы хотите чего-то вполне разумного и несложного, но сделать это не получится.

    Опять же, стоит заметить, что библиотеки вроде jOOλ и StreamEx решают большинство таких проблем.


    17) Любую ли лямбду можно заменить на анонимный класс?

    В Java 8 можно любой анонимный класс, который реализует один абстрактный метод заменить на лямбду выражение,

    если анонимный класс реализует два абстрактных метода, то заменить на лямбду будет невозможно.

    Если вы проект перевели на Java 8, то такие измения безопасные.

    Idea дает возможность поменять все анонимные классы на лямбды.

    19) [императивный vs [декларативный [подход

    [Императивный стиль

    Это такой стиль программирования, при котором вы описываете, как добиться желаемого результата. Например я пишу:
    — поставь сковородку на огонь;

    — возьми два яйца (куриных);

    — нанеси удар ножом по каждому;

    — вылей содержимое на сковородку;

    — выкинь скорлупу;


    Это что ни на есть декларативный стиль, но при этом с примесью императивного.
    [Декларативный стиль
    Такой стиль, в котором вы описываете, какой именно результат вам нужен.
    Тут я просто пишу:
    — приготовь яичницу
    И получатель такого сообщения уже сам разбирается, какие шаги для этого надо предпринять.

    Почему пример из части про императивность на самом деле с примесью декларативности?

    Ну хотя бы потому что получатель должен знать, что такое сковорода и яйца.

    Императивный подход (как): Я вижу, что тот угловой столик свободен. Мы пойдём туда и сядем там.
    Декларативный подход (что): Столик для двоих, пожалуйста.
    Императивный подход означает то, как вы займёте место. Вы должны перечислить все шаги этого процесса.

    Декларативный же подход заявляет, что вам нужен столик на двоих


    20) Что такое default методы в интерфейсе и для чего они были введены?

    [Default-методы появились Java 8.

    Default-метод — это метод, который реализуется прямо в интерфейсе, его помечают ключевым словом default.

    default-методы упрощают рефакторинг — а именно, добавление новых методов.

    До Java 8 все методы в интерфейсах были абстрактными. К чему это вело?
    К тому, что при добавлении нового метода в интерфейс приходилось править все классы,

    реализующие интерфейс — реализовывать метод в этих классах. Это было неудобно. А в Java 8 (в классы ядра) захотели ввести новые методы в старые

    интерфейсы. Так что ввели ключевое слово default и эти методы сделали default.

    Например, в интерфейсе java.lang.Iterable появились новые default-методы forEach() и spliterator():

    какой метод унаследует класс, реализующий два интерфейса, если оба из них содержат default-методы с одинаковыми именами.

    Чтобы не было неопределенности (и чтобы скомпилировался код), мы обязаны переопределить в Kentavr метод sleep()

    , причем можно просто вызвать в нем метод sleep() любого из интерфейсов — Man либо Animal, указав через точку и super, чей именно метод нужен:


    21) К каким переменным есть доступ из лямбда-выражения?
    [Доступ к переменным внешней области действия из лямбда-выражения очень схож к доступу из анонимных объектов. Можно ссылаться на:

    1) неизменяемые (effectively final - не обязательно помеченные как final) локальные переменные;

    2) поля класса;

    3) статические переменные.

    К методам по умолчанию реализуемого функционального интерфейса обращаться внутри лямбда-выражения запрещено.

    effectively final локальные переменные

    В в лямбда-выражениях стоит использовать внешние (относительно выражения) неизменяемые значения, а не внешние переменные,

    значение и внутреннее состояние которых могут меняться. Под внешними неизменяемыми значениями, соответственно,

    подразумеваются effectively final локальные переменные и поля примитивных типов, а также effectively final объекты,

    внутреннее состояние которых не будет меняться.
    Связано это с тем, что Streams и лямбда-выражения проектировались из расчета на их многопоточное использование.

    22) Любой анонимный класс можно заменить на лямбду?

    В Java 8 можно любой анонимный класс, который реализует один абстрактный метод заменить на лямбду выражение,

    если анонимный класс реализует два абстрактных метода, то заменить на лямбду будет невозможно.

    23)

    24) Отличие [BinaryOperator от Function.

    BinaryOperator возвращает тип данных тот же над которым производились действия.

    Функциональный интерфейс Function представляет функцию перехода от объекта типа T к объекту типа R.


    25) Что такое ленивая инициализация стрима?

    Отложенная (ленивая) инициализация (англ. ... Lazy initialization) — приём в программировании,

    когда некоторая ресурсоёмкая операция (создание объекта, вычисление значения)

    выполняется непосредственно перед тем, как будет использован её результат. Ленивая инициализация-это оптимизация производительности,

    при которой вы откладываете (потенциально дорогостоящее) создание объекта до тех пор, пока оно вам действительно не понадобится.

    Секрет «ленивости» Stream в том, что каждый раз, когда вы используете Stream,

    он соединяет несколько промежуточных операций и присоединяет конечную операцию в конце.

    Такие методы, как map () и filter (), являются промежуточными операциями, и при их вызове немедленно возвращается другой объект Stream.

    Для таких методов, как reduced () и findFirst (),

    они являются конечными операциями, а реальные операции выполняются при их вызове для получения требуемых значений.

    26) Две терминальные операции в одном выражении?

    Терминальная операция это, то что запускает стрим и в тоже самое время она получает результат, а значит она должна быть одна


    27) Что такое терминальная операция?

    Это операции, которые как бы «запускают» наш стрим. Мы можем создать стрим и добавить в него любое количество промежуточных операций,

    но они не будут выполнены пока не будут добавлена терминальная операция.
    Выше мы уже применяли одну из самых популярных операций — forEach(Consumer action).

    В нее попадают все прошедшие через стрим объекты и обрабатываются в соответствие с тем алгоритмом, что будет указан в Consumer.

    28) Что возвращают промежуточные операции над стримом?

    Промежуточные (“intermediate”, ещё называют “lazy”) операции — обрабатывают поступающие элементы и возвращают стрим.

    Промежуточных операторов в цепочке обработки элементов может быть много

    Промежуточные операции следует воспринимать как «отложенные», т.е. они не меняют сами данные, а только задают правила их изменения.

    А терминальные как раз инициируют всю цепочку преобразований и возвращают модифицированные данные.

    29) Для чего нужны параллельные стримы?

    Stream API предоставляет очень простой механизм для выполнения операций над потоком параллельно:

    входной поток разбивается на части, если это возможно,

    и каждая такая часть обрабатывается параллельно с остальными, в раздельных нитях.

    Кроме последовательных потоков Stream API поддерживает параллельные потоки.

    Распараллеливание потоков позволяет задействовать несколько ядер процессора (если целевая машина многоядерная) и тем

    самым может повысить производительность и ускорить вычисления. В то же время говорить,

    что применение параллельных потоков на многоядерных машинах однозначно повысит производительность - не совсем корректно.

    В каждом конкретном случае надо проверять и тестировать.

    есть 3 [минуса

    1) если у вас есть какое-то количество потоков, обрабатывающих запросы пользователей и в каждом потоке выполняются какие-либо операции над parallelStream(),

    эти потоки будут вынуждены ждать друг друга

    2) уследить за нежелательными эффектами от влияния нитей друг на друга становится ещё сложнее.

    3) параллельность обработки вообще не гарантируется и зависит от источника данных.

    А прирост производительности зависит от его способности корректно разделить набор данных на независимые блоки.
    30) Что такое анонимный класс.

    [Анонимный класс ([anonymous class) - это локальный класс без имени. Используется тогда, когда нужно переопределить метод класса или интерфейса.

    31) Что такое [ФИ [функциональный интерфейс и для чего он нужен и зачем были добавлены?

    Если интерфейс в Java содержит один и только один абстрактный метод, то он называется функциональным.

    Этот единственный метод определяет назначение интерфейса.

    Это интерфейс, котрый определяет сторого один метод.

    аннотанация @FunctionalInterface введена для обазначения интерфейса, функциональным, это анотанация используется для того, чтобы

    избежать случайного добавления абстрактных методов в функциональном интерфейсе. Она не обязательна, но является хорошей практикой чистого кода

    [ФИ позволяют нам использовать лямбда выражения для создания экземпляра таких интерфейсоф

    Интерфейс Runnable является одним из самых популярных, с одним методом run().

    интерфейс может содержать сколько угодно default методов и при этом оставатьсяя функциональным, потому, что default методы не абстрактные


    32) Какой аннотацией помечается функциональный интерфейс?

    аннотанация @FunctionalInterface

    33) Сколько дефолтных методов и статических методов, сртатических полей в интерфейсе?

    Сколько хочешь, статик методы переопределять нельзя. Статик поля возможны, но это плохая практика.


    34) Где находятся функциональные интерфейсы?

    В Java все стандартные функциональные интерфейсы лежат в пакете java.util.function

    35) [СВОЙСТВА [ФИ Перечислить основные семейства функ.интерфейсов?

    Делятся на 7 семейств

    1) [Consumer - потребители, те кто принимают(объект типа Т, совершают некотрые действия) но не возвращают в замен. Его подвиды IntConsumer, LongConsumer, DoubleConsumer они есть

    потому, что дженерики не могут парметризоваться примитивами.

    2) [Supplir - поставщики, они не принимают ни какое значение, а просто возращают какоето значение типа Т.

    3) [Predicate - приниает выражение какого то типа (для проверки некоторого условия) а наружу выдает булевское значение. есть для примитивов, есть булевские

    4) Function - принимает аргумент типа Т и приводит его к объекту типа R, который и возвращается как результат, в общем случаее типы разные. Бывает принимают два параметра. могут стоять примитивы

    5) Operator - это частный случай функции, когда на вход подается значение одного и того же типа.

    Унарный оператор принимает один параметр а Бинарный два параметра отдельные интерфейсы над лонгами и даблами

    6) BinaryOperator принимает в качестве параметра два объекта типа T, выполняет над ними бинарную операцию и возвращает ее результат также в виде объекта типа T.

    7) UnaryOperator принимает в качестве параметра объект типа T, выполняет над ними операции и возвращает результат операций в виде объекта типа T.

    36) [ФИ Функциональные интерфейсы что они принимают и что возвращают?

    1) [Consumer - потребители, те кто принимают (объект типа Т, совершают некотрые действия) но не возвращают в замен. Его подвиды IntConsumer, LongConsumer, DoubleConsumer они есть

    потому, что дженерики не могут парметризоваться примитивами.

    2) [Supplir - поставщики, они не принимают ни какое значение, а просто возращают как оето значение типа Т.

    3) Predicate - приниает выражение (для проверки некоторого условия) какого то типа а наружу выдает булевское значение. есть для примитивов, есть булевские

    4) Function - принимает аргумент типа Т и приводит его к объекту типа R, который и возвращается как результат, в общем случаее типы разные.

    5) Operator - это частный случай функции, когда на вход подается значение одного и того же типа. Унарный оператор принимает один параметр а Бинарный два параметра

    отдельные интерфейсы над лонгами и даблами

    6) BinaryOperator принимает в качестве параметра два объекта типа T, выполняет над ними бинарную операцию и возвращает ее результат также в виде объекта типа T.

    7) UnaryOperator принимает в качестве параметра объект типа T, выполняет над ними операции и возвращает результат операций в виде объекта типа T.


    37) Какие есть способы [инстацировать функциональные интерфейсы (анонимный класс, лямбда выражения, ссылки на методы)?

    Функциональные интерфейсы можно инcтанцировать тремя способами

    1) можно завести именнованный или анонимный класс, но это громоздко

    2) можно использовать лямбда выражение. Обявляем имена параметра и тело метода sqware = x-> {return x * x}; обязательно точка с запятой.

    Если тело метода из одного метода, то скобки можно опустить а если есть ретерн то добавляем скобки

    вопрос к каким переменным и как можно обращатся в лямбда выражении

    1) к параметрам лямбды, а также свободно объявлять и использовать любые переменные х -> x * x;

    2) к полям(переменным) того класса в нутри котого объявлена лямбда, можно как читать, так и писать. IntSupplier sequense = () -> counter++;

    3) к переменным которые объявлены внутри метода где объявлена лямбда. Но есть ограничения переменные должны быть эффективно финальные

    т.е. значение им должно присвоено ровно один раз до объявления лямбды, после чего оно менятся уже не может.(Типа мы написали final)int bonus = 10; IntUnaryOperator bonusAdder = (x) -> x + bonus;

    !!! Лямбдам нельзя присваивать новые значения переменным содержащимся в ее методе.

    Для обхода этого ограниечения используют трюк с обходом массива единичной длины.

    3) с помощью ссылки на метод

    ToIntFunction intParser = Integer :: parseInt;

    Consumer printer= System.out:: println;

    Function objectStringFunction = Object:: toString;

    IntFunction arrayAllocator = String[] :: new;

    Есть нюансы!!!!! М можем ссылаться на статический метод указывая имя класса двоеточие и имя статического метода.

    Если на нестатический метод, указывая конкретно объект и два двоеточия

    Есть вариант указать имя класса два двоиточия и имя нестатического метода, но тогда первый указываемый параметре будет тем объектом на который не стаитический метод будет вызван.

    Можно ссылаться на конструктор. Когда пишут имя класса два двоеточия и ключевое слово new


    38) [?лямбда Что такое лямбда выражение и ссылка на метод. Как они связаны с анонимным классом.

    Лямбда представляет набор инструкций, которые можно выделить в отдельную переменную

    и затем многократно вызвать в различных местах программы.

    Основу лямбда-выражения составляет лямбда-оператор, который представляет стрелку ->.

    Этот оператор разделяет лямбда-выражение на две части: левая часть содержит список параметров выражения,

    а правая собственно представляет тело лямбда-выражения, где выполняются все действия.

    Лямбда-выражение не выполняется само по себе, а образует реализацию метода, определенного в функциональном интерфейсе.

    По факту лямбда-выражения являются в некотором роде сокращенной формой внутренних анонимных классов, которые ранее применялись в Java.

    Если существующий в классе метод уже делает все, что необходимо,

    то можно воспользоваться механизмом method reference (ссылка на метод) для непосредственной передачи этого метода. на

    1) статический метод; имя_класса::имя_статического_метода для статического метода;

    2) на метод экземпляра объекта; объект_класса::имя_метода для метода экземпляра;

    3) на конструкторе. название_класса::new для конструктора.

    Ссылки на методы потенциально более эффективны, чем использование лямбда-выражений. Кроме того,

    они предоставляют компилятору более качественную информацию о типе и при возможности выбора

    между использованием ссылки на существующий метод и использованием лямбда-выражения,

    следует всегда предпочитать использование ссылки на метод.


    1   2   3   4


    написать администратору сайта