Функциональные интерфейсы
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 39 из 87.
Функциональный интерфейс — это интерфейс, который содержит ровно один абстрактный метод. Это ограничение в один метод делает функциональные интерфейсы особенными, так как они могут быть реализованы с помощью лямбда-выражений, что позволяет использовать более лаконичный стиль написания кода.
Java предоставляет аннотацию @FunctionalInterface для явного обозначения интерфейса как функционального. Хотя эта аннотация необязательна, она помогает компилятору обнаруживать ошибки, если вы случайно добавите второй абстрактный метод:
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}Вы можете реализовать функциональный интерфейс традиционным способом с помощью класса или более лаконично с помощью лямбда-выражения:
// Традиционная реализация
Calculator adder = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// Лямбда-выражение (намного короче!)
Calculator adder = (a, b) -> a + b;
System.out.println(adder.calculate(5, 3)); // 8Функциональные интерфейсы все еще могут иметь методы по умолчанию и статические методы, так как они не учитываются в правиле одного абстрактного метода. Пакет Java java.util.function предоставляет множество встроенных функциональных интерфейсов, таких как Predicate, Function и Consumer, с которыми вы будете часто сталкиваться при работе со стримами и коллекциями.
Задание
ЛегкоДавайте создадим систему трансформации строк, используя функциональные интерфейсы и лямбда-выражения. Вы создадите гибкий обработчик текста, который может применять различные преобразования к строкам — и все это на базе одного функционального интерфейса.
Вы организуете свой код в трех файлах:
StringTransformer.java: Определите функциональный интерфейс, который представляет любую операцию трансформации строки. Отметьте его аннотацией@FunctionalInterface, чтобы гарантировать, что он останется функциональным. Ваш интерфейс должен объявлять один абстрактный метод с именемtransform, который принимает String и возвращает String.TextProcessor.java: Создайте класс, который использует ваш функциональный интерфейс для обработки текста. У него должно быть поле для храненияStringTransformerи конструктор для его инициализации. Включите метод с именемprocess(String text), который применяет трансформер к заданному тексту и возвращает результат. Такая архитектура позволяет внедрять любое поведение трансформации через конструктор.Main.java: Объедините все вместе, создавая различные трансформации с помощью лямбда-выражений. Вы получите два входных значения: текстовую строку и тип операции (upper,lowerилиreverse).В зависимости от типа операции создайте
TextProcessorс соответствующей лямбдой:upper: преобразует текст в верхний регистрlower: преобразует текст в нижний регистрreverse: переворачивает текст (подсказка: используйтеStringBuilder)
Затем вызовите
process()с входным текстом и выведите результат в формате:Result: [transformed text]
Вы получите два входных значения: текст для трансформации (String) и тип операции (String).
Обратите внимание, как один и тот же класс TextProcessor может выполнять совершенно разные операции в зависимости от того, какую лямбду вы передаете — в этом и заключается мощь функциональных интерфейсов!
Шпаргалка
Функциональный интерфейс — это интерфейс, содержащий ровно один абстрактный метод. Его можно реализовать с помощью лямбда-выражений для написания лаконичного кода.
Используйте аннотацию @FunctionalInterface, чтобы пометить интерфейс как функциональный (необязательно, но рекомендуется):
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}Функциональные интерфейсы могут быть реализованы традиционным способом или с помощью лямбда-выражений:
// Традиционная реализация
Calculator adder = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// Лямбда-выражение
Calculator adder = (a, b) -> a + b;
System.out.println(adder.calculate(5, 3)); // 8Функциональные интерфейсы могут иметь методы по умолчанию (default) и статические методы, не нарушая правило единственного абстрактного метода.
Пакет Java java.util.function предоставляет встроенные функциональные интерфейсы, такие как Predicate, Function и Consumer.
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine();
String operation = scanner.nextLine();
TextProcessor processor;
// TODO: В зависимости от типа операции создайте TextProcessor с соответствующим лямбда-выражением:
// - "upper": преобразует текст в верхний регистр
// - "lower": преобразует текст в нижний регистр
// - "reverse": переворачивает текст (подсказка: используйте StringBuilder)
// TODO: Вызовите process() с входным текстом и выведите результат
// Формат вывода: "Result: [transformed text]"
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»