Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по 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, с которыми вы будете часто сталкиваться при работе со стримами и коллекциями.

challenge icon

Задание

Легко

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

Вы организуете свой код в трех файлах:

  • 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]"
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование