Главная страница

Функциональные Интерфейсы. Функциональные Интерфейсы. Streams Что такое Функциональные интерфейсы и их основные типы


Скачать 15.62 Kb.
НазваниеФункциональные Интерфейсы. Streams Что такое Функциональные интерфейсы и их основные типы
Дата06.09.2022
Размер15.62 Kb.
Формат файлаdocx
Имя файлаФункциональные Интерфейсы.docx
ТипДокументы
#665070

Функциональные Интерфейсы. Streams

1. Что такое Функциональные интерфейсы и их основные типы.
Интерфейс называется функциональным если у него есть ровно один абстрактный метод (при этом default и static методов может быть сколько угодно - они не в счет)

Такой интерфейс можно пометить аннотацией @Functinalinterface

Основные типы ФИ:

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

2) Supplier - поставщики. Ничего не принимают, но возвращают T.

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

4) Function - принимает T и приводит его к объекту R. Бывает принимают два параметра. могут стоять примитивы
5) Operator - частный случай Функции. Принимает и отдает T
5) BinaryOperator - принимает два объекта T, выполняет над ними операцию и возвращает T
6) UnaryOperator - принимает объект T, выполняет операции и возвращает T

2. Что такое лямбда выражение?

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

Основу лямбда-выражения составляет лямбда-оператор -> он разделяет лямбда-выражение на две части: левая часть содержит список параметров, а правая тело лямбда-выражения, где выполняются все действия.
3. Что такое Стрим?

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

Формат работы со стримом: Получение стрима -> 0 или более промежуточных операторов -> Терминальный оператор. Обработка (начало вычисления элементов стрима) происходит только после терминального оператора.
4. Группы операторов Stream

Операторы можно разделить на две группы:

Промежуточные или КОНВЕЙЕРНЫЕ операторы(“intermediate”, ещё называют “lazy”) — обрабатывают элементы и возвращают стрим.

Терминальные (“terminal”, еще называют “eager”) — запускают обработку элементов стрима промежуточными методами и в завершении выполняется терминальный оператор.
5. Сколько может быть промежуточных и терминальных операторов?

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

А терминальный оператор может быть только один.
6. Сколько раз можно использовать Stream?

Stream не может быть использованы повторно. Как только была вызвана терминальная операция, stream закрывается.
7. Stream для примитивов

Кроме универсальных объектных существуют особые виды стримов для работы с примитивными типами данных int, long и double: IntStream, LongStream и DoubleStream.

Эти примитивные стримы работают так же, как и обычные объектные, но со следующими отличиями: используют специализированные лямбда-выражения, например, IntFunction или IntPredicate вместо Function и Predicate; А также поддерживают дополнительные конечные операции sum(), average(), mapToObj().


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


Метод, логика которого реализована в самом интерфейсе. Имеют ключевое слово default. Появились в Java 8 для упрощения добавление новых методов в интерфейс - не нужно править все классы реализующие интерфейс, сохраняя при этом обратную совместимость с уже написанным кодом.

9. Как взаимосвязаны лямбда и функциональный интерфейс?

ФИ. это И. с ровно 1 абстрактным методом. Его и придумали как раз для того, чтобы появилась такая фишка языка как Лямбда. Л. или Лямбда-выражение это компактная и читабельная запись определения абстрактного метода и создание анонимного класса его реализующего. По сути это синтаксический сахар, но очень удобный. А еще это закос в функциональное программирование.
10. Ссылка на метод. парам::парам

Если существующий в классе метод уже делает все, что необходимо, то можно воспользоваться механизмом method reference (ссылка на метод). Т.е. можно заменить выражение x -> metod(x) на:
1) статический метод; имя_класса::имя_статического_метод
2) на метод экземпляра; объект_класса::имя_метод

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

Если есть возможность лямбду заменить ссылкой на метод, то лучше это делать.
11. Любой анонимный класс можно заменить на лямбду?

Только тот, который реализует 1 абстрактный метод. А если 2 и более, то заменить на лямбду нельзя.

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

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

Stream API так и работает: мы указываем промежуточные операции, которые нам необходимо произвести и в конце следует завершающая или терминальная операция, которая запускает все вычисления. Промежуточные: map () и filter (), Терминальные: counter(), forEach()

13. Расскажите про Comparator и Comparable?
см 22.

14. Что такое функциональное программирование? Плюсы / минусы, где применяется?
ФП - одна из парадигм программирования в котором код, это последовательное применение функций, а не инструкций. Элементы ФП есть практически во всех языках. Но есть языки по большой части относящиеся к ФП: Scala, Haskell, Lisp.
Плюсы: код более понятный, предсказуемый, легкий для чтения (при небольших объемах). Поддерживаются ленивые конструкции - производительность
Минусы: легко писать простые функции, но сложно из них собрать целое приложение
- слишком абстрактный код, поэтому в большом коде разобраться сложно
- большой объем затрачиваемой памяти - не хранят состояние, поэтому нужно каждый раз создавать объекты
Где используется:
Когда нужно выполнять множество различных операций с одним и тем же набором данных: искусственный интеллект, машинное обучение, моделирование речи и зрения

15. Все способы реализации функционального интерфейса:
1. С помощью анонимного класса
2. С помощью лямбда - выражения.
3. С помощью ссылки на метод
4. С помощью обычного класса, путем имплементации

16. Приведи пример терминальной и промежуточной операции над стримом
Промежуточные операции:
filter(Predicate predicate): фильтрует элементы в соответствии с условием в предикате.
limit(long maxSize): оставляет в потоке только maxSize элементов
map(Function mapper): преобразует элементы типа T в элементы типа R
flatMap(Function mapper): аналог map, но может создавать из 1 элемента - несколько
skip(long n): пропускает первые n элементов.
sorted(Comparator comparator): сортирует элементы потока в соответствии с компаратором
distinct() - удаляет дубликаты
peek() - применяет функцию к каждому элементу стрима

Терминальные:
findFirst() (findAny) - первый (любой) элемент из стрима (в виде Optional)
max() (min) (Comparator): возвращает максимальный (минимальный) элемент (Optional)
long count(): количество элементов.
anyMatch() (noneMatch, allMatch) - true, если условие выполняется хотя бы для одного (не выполняется ни для одного, выполняется для всех) элемента
forEach(Consumer) (forEachOrdered): Применить функцию к каждому объекту, порядок при параллельном выполнении не гарантируется (гарантируется)
toArray(): массив из элементов
reduce() — преобразование всех элементы стрима в один объект (посчитать сумму всех элементов, найти минимальный элемент)
collect(Collector): преобразует stream в Коллекцию. У Collectors есть много удобных стат. методов для группировки: groupingBy(), counting(), summing() и другие которые возвращают Collector


17. В чем разница map и flatMap?
Общее:
- это промежуточные операции над stream, поэтому возвращают поток
- преобразовывает элементы из одного типа в другой
Отличия:
- результат работы map над 1 элементом входящего потока это всегда 1 элемент результирующего потока
- в то время, как flatMap производит произвольное число (0 и более) значений для каждого элемента входного потока
Типичное употребление flatMap: это “сглаживание” входного потока в плоский. Т.е. если входящий поток состоит из списков (массивов), то результатом будет плоский стрим из всех элементов этих списков (массивов).

18. К каким переменным можно обращаться внутри лямбды?
1) К параметрам лямбды, а также свободно объявлять и использовать любые переменные
2) К полям (переменным) того класса внутри которого объявлена лямбда, можно как читать, так и писать. В том числе и к статическим
3) К переменным, которые объявлены внутри метода где объявлена лямбда.
Но есть ограничения - переменные должны быть эффективно финальные. т.е. значение им должно присвоено ровно один раз до объявления лямбды, и после оно меняется не может. Для обхода этого ограничения используют трюк с массивом единичной длины.

19. Способы как получить стрим:
Классический: из коллекции | collection.stream(), collection.parallelStream()
Из значений | Stream.of(значение1, ... значениеN)
Из массива | Arrays.stream(массив)
Из файла (каждая строка в файле - отдельным элементом в стриме) Files.lines(путь_к_файлу)
Из строки | "строка".chars()
Через Stream.builder: | Stream.builder().add(...)....build()
Через Stream.iterate | Stream.iterate(начальное_условие, выражение_генерации)
Через Stream.generate | Stream.generate(выражение_генерации)
В iterate задается начальное условие и выражение - получение следующего значения из предыдущего, то есть Stream.iterate(1, n -> n + 1) будет выдавать значения 1, 2, 3, 4, ... N.
Stream.generate служит для генерации константных и случайных значений, он просто выдает значения соответствующие выражению.

20. Какие бывают стримы:
1) конечные и бесконечные
2) последовательные и параллельные
3) объектные и примитивные
Параллельные потоки позволяет задействовать несколько ядер процессора и тем самым может повысить производительность. НО в каждом конкретном случае надо проверять и тестировать. Чтобы получить параллельный стрим, нужно либо вызвать метод parallelStream() вместо stream(), либо распарралелить существующий.

21. Методы forEach() и forEachOrdered():
Метод forEach не гарантирует порядок обработки элементов потока.
В то время как forEachOrdered гарантирует обработку элементов в порядке их добавления в stream. Актуально это, в первую очередь, в параллельных stream-ах.

22. В чем разница между интерфейсами Comparable и Comparator?
- Comparable обеспечивает единую последовательность сортировки для класса.
Comparator предоставляет возможность создания нескольких последовательностей сортировки.
- Comparable влияет на исходный класс, т.е. модифицируется фактический класс.
Comparator не влияет на исходный класс, т.е. фактический класс не изменяется.
- Comparable предоставляет метод compareTo() для сортировки элементов.
Comparator предоставляет метод compare() для сортировки элементов.
- Comparable в пакете java.lang. Comparator в пакете java.util.
- Comparable - имплементится самим классом, когда нужен натуральный порядок сортировки. Пример - класс String, Intreger. Comparator - имплементится другими классами. Дает возможность отделить реализацию сравнения от класса и сделать несколько реализаций

23. Методы peek и forEach в чем разница?
По сути оба метода делают одно и тоже - производят действие над каждым элементом потока. Но, метод peek промежуточный, его часто используют для отладки, чтобы посмотреть промежуточное состояние потока. Метод forEach же терминальный.

24. В каком пакете находится Stream?
Stream API являются составляющей пакета java.util.stream

25. Чем Stream отличается от итератора?
Итератор это простой объект который умеет выдавать элементы по одному.
Stream гораздо более сложный и навороченный, у него огромное количество методов. Он содержит не только средства обхода элементов, но и 1) описания 2) обработки 3) преобразования последовательности элементов

26. В чем разница между Collection и Stream?
- Collection для хранения, Stream для обработки.
- Коллекции позволяют работать с элементами по-отдельности, стримы так делать не могут. Вместо этого дают возможность выполнять функции над данными как над одним целым.
- Collection - это прежде всего воплощение Структуры Данных. Например, Set это множество уникальных элементов, тогда как Stream, это прежде всего абстракция необходимая для реализации конвейера вычислений.

27. Как получить стрим диапазона чисел?
IntStream smalInteger = IntStream.range(0, 100)
IntStream smallInteger2 = IntStream.rangeClosed(0, 100) - включает последний элемент (100)

28. Можно ли конкатенировать стримы? Если да, то каким методом?
Можно ли получить пустой стрим?

Да можно!
IntStream cobiedStream = IntStream.concat(stream1,stream2) - конкатенация
IntStream empty = IntStream.empty() - пустой стрим

29. Отличия Абстрактного класса от интерфейса
Интерфейс определяет только поведение. Он не сообщает ничего про объект, который будет его реализовывать. Абстрактный же класс описывает некий абстрактный объект (автомобиль, человека, кота и т. д.), а не только поведение.

30. Что нельзя создать в анонимном классе?
- статические переменные и методы
- конструкторы (ни определять, ни переопределять). Аргументы в круглых скобках, стоящих за именем родительского класса, неявно передаются конструктору родительского класса.


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