1.4. FP, Lambda, Stream API Flashcards
Что такое lambda-выражение?
Лямбда-выражение - это краткая форма записи реализации абстрактного метода функционального интерфейса, которая может быть передана в качестве параметра.
- Синтаксис: (параметры) -> { тело }.
- В Java лямбда-выражение выполняет роль анонимной функции.
Что такое функциональные интерфейсы?
Функциональный интерфейс - это интерфейс, который содержат только один абстрактный метод, не считая методы класса Object.
- Обозначается аннотацией @FunctionalInterface.
- Примеры: Runnable, Comparator, Function, Supplier, Operator.
Перечислите функциональные интерфейсы из пакета java.util.function.
- Supplier - ничего не принимает, возвращает объект.
- Consumer (BiConsumer) - принимает объект и выполняет действие с ним, ничего не возвращает.
- Predicate (BiPredicate) - проверяет условие, возвращает boolean.
- Function (BiFunction) - преобразует входной параметр в значение другого типа.
- UnaryOperator (BinaryOperator) - разновидность Function, где входной и выходной типы совпадают.
Что такое функции высшего порядка?
Функции высшего порядка — это функции, которые принимают или возвращают другие функции.
Какие функциональные интерфейсы из пакета java.util.function поддерживают функции высшего порядка?
- Function, BiFunction: методы andThen(), compose().
- Predicate, BiPredicate: методы and(), or(), negate().
- Consumer, BiConsumer: метод andThen().
compose() - сначала выполнить указанную функцию, а затем применить текущую. Последовательность происходит в обратном порядке, чем при использовании andThen.
negate() - меняет результат текущего предиката на противоположный (true → false, false → true).
Что такое ссылки на методы?
Ссылки на методы (method references) — это сокращенный способ записи существующих методов в лямбда-выражении.
Типы ссылок:
- Статический метод: СlassName::method
- Метод объекта: instance::method
- Конструктор: ClassName::new
Сигнатура ссылки на метод/конструктор должна совпадать с сигнатурой абстрактного метода функционального интерфейса.
Что такое ссылки на конструкторы?
Ссылки на конструкторы (ClassName::new) используются для создания объектов.
- Без параметров: реализует Supplier<T>.</T>
- С параметрами: реализует Function<T, R> или BiFunction<T, U, R>.
Расскажите о зоне видимости переменных в lambda – выражениях?
- Поля класса и статические переменные: доступны для чтения и изменения.
- Локальные переменные: доступны только для чтения, должны быть final или effectively final.
- Переменные внутри лямбда-выражения: доступны только внутри.
Как быть в ситуации, если внутри lambda - выражения операторы могут выкинуть исключение?
- Преобразовать исключение в RuntimeException в try-catch.
- Использовать функциональный интерфейс, который декларирует checked exceptions в throws
т.к. в Java нельзя выбросить checked исключение из метода, если оно не указано в throws.
Что такое Stream API?
Stream API - это инструмент для обработки данных в функциональном стиле через цепочку операций. Позволяет: фильтровать, сортировать, преобразовывать, агрегировать и параллельно обрабатывать данные.
Особенности: потоки не изменяют исходные данные.
Расскажите, какие шаблоны проектирования используются внутри Stream API? (Builder, Strategy, Decorator, Factory Method, Pipeline).
- Builder - позволяет пошагово создавать сложные объекты, давая пользователю возможность комбинировать компоненты.
- Strategy - обеспечивает выбор алгоритма выполнения во время работы программы.
- Decorator - добавляет новую функциональность объекту, не изменяя его структуру.
- Factory Method - создание потоков (Stream.of()) с использованием подклассов вместо прямого создания экземпляров.
- Pipeline - конвейерная обработка данных через комбинацию промежуточных и терминальных операций.
Объясните, где они используются в Stream API.
- Builder - создает цепочки операций (map(), filter(), sorted()) для обработки данных поэтапно.
- Strategy - позволяет выбирать алгоритм выполнения (stream() или parallelStream()).
- Decorator - методы filter(), map(), flatMap() и другие конвейерные операции действуют как декораторы, добавляя функциональность к потоку данных без изменения исходного источника данных.
- Factory Method - создает потоки через методы Stream.of() и Arrays.stream().
- Pipeline - представляет собой последовательность конвейерных операций, где каждая операция обрабатывает поток данных и передает результат следующей операции в цепочке.
Что такое конвейерные и терминальные операции?
- Конвейерные операции - это промежуточные операции, которые выполняют преобразование данных и возвращают новый поток. Эти операции выполняются только после вызова терминальной операции.
- Терминальные операции - инициируют выполнение всех промежуточных операций, возвращают результат и закрывают поток.
Перечислите конвейерные (промежуточные) методы Stream API.
- filter() - фильтрует элементы потока по предикату.
- map() - преобразует каждый элемент потока, применяя функцию.
- flatMap() - объединяет вложенные потоки в один.
- distinct() - удаляет дубликаты из потока.
- sorted() - сортирует элементы потока по компаратору, по умолчанию (natural order).
- peek() - выполняет действие для каждого элемента потока без изменения самого потока. Используется для отладки.
- limit() - ограничивает количество элементов в потоке до заданного количества.
- skip() - пропускает первые n элементов потока.
Дополнительные конвейерные методы для примитивных потоков:
- mapToInt(), mapToLong(), mapToDouble() - преобразуют элементы потока в поток примитивов int, long, double.
- flatMapToInt(), flatMapToLong(), flatMapToDouble() - преобразует элементы в поток примитивов int, long, double, затем объединяет все потоки в один.
Перечислите терминальные методы Stream API.
- forEach() - выполняет действие для каждого элемента потока.
- collect() - собирает элементы потока в коллекцию, строку или другой контейнер.
- reduce() - выполняет агрегацию элементов, сводя их к одному результату.
- count() - возвращает количество элементов в потоке.
- toArray() - преобразует поток в массив.
- min/max() - возвращает минимальный/максимальный элемент потока согласно компаратору.
- findFirst() - возвращает первый элемент потока или Optional.empty.
- findAny() - возвращает любой элемент потока.
- allMatch() - проверяет, что все элементы соответствуют предикату.
- noneMatch() - проверяет, что ни один элемент не соответствует предикату.
- anyMatch() - проверяет, что хотя бы один элемент соответствует предикату.