0Pricing
Java Academy · Урок

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

Создавайте собственные интерфейсы с @FunctionalInterface

«Пользовательские функциональные интерфейсы» — бесплатный урок Java Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.

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

Функциональный интерфейс содержит ровно один абстрактный метод (SAM). Именно этот единственный метод реализует лямбда-выражение.

  • Методы по умолчанию и статические методы не учитываются при проверке ограничения.
interface Greeter {
    String greet(String name);
}

public class Main {
    public static void main(String[] args) {
        Greeter g = name -> "Hello, " + name;
        System.out.println(g.greet("Ada"));
    }
}

Аннотация @FunctionalInterface

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

@FunctionalInterface
interface Calculator {
    int compute(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        Calculator add = (a, b) -> a + b;
        System.out.println(add.compute(3, 4));
    }
}

Зачем нужна эта аннотация

Аннотация документирует намерение и защищает контракт. Без неё интерфейс всё равно работает как функциональный, но коллега может нарушить его, добавив ещё один абстрактный метод.

@FunctionalInterface
interface Transformer {
    String apply(String input);
}

public class Main {
    public static void main(String[] args) {
        Transformer reverse = s -> new StringBuilder(s).reverse().toString();
        System.out.println(reverse.apply("abc"));
    }
}

Пользовательский интерфейс с обобщениями

Ваш интерфейс может быть обобщённым, как и встроенные интерфейсы.

@FunctionalInterface
interface Converter<S, T> {
    T convert(S source);
}

public class Main {
    public static void main(String[] args) {
        Converter<String, Integer> toInt = Integer::parseInt;
        System.out.println(toInt.convert("123") + 1);
    }
}

Методы по умолчанию разрешены

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

@FunctionalInterface
interface Operation {
    int apply(int x);

    default Operation then(Operation next) {
        return x -> next.apply(this.apply(x));
    }
}

public class Main {
    public static void main(String[] args) {
        Operation inc = x -> x + 1;
        Operation dbl = x -> x * 2;
        System.out.println(inc.then(dbl).apply(5));
    }
}

Статические методы тоже разрешены

Статические методы могут выступать в роли фабрик, подобно Function.identity().

@FunctionalInterface
interface Mapper {
    int map(int x);

    static Mapper identity() {
        return x -> x;
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(Mapper.identity().map(99));
    }
}

Выбрасывание проверяемых исключений

Если ваш абстрактный метод объявляет проверяемое исключение, лямбда-выражение может его выбросить. Встроенный Function этого не позволяет, и это одна из причин определить собственный интерфейс.

@FunctionalInterface
interface RiskyParser {
    int parse(String s) throws NumberFormatException;
}

public class Main {
    public static void main(String[] args) {
        RiskyParser p = Integer::parseInt;
        System.out.println(p.parse("77"));
    }
}

Передача пользовательских интерфейсов методам

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

@FunctionalInterface
interface IntCombiner {
    int combine(int a, int b);
}

public class Main {
    static int reduce(int[] arr, IntCombiner c) {
        int acc = arr[0];
        for (int i = 1; i < arr.length; i++) acc = c.combine(acc, arr[i]);
        return acc;
    }

    public static void main(String[] args) {
        int[] data = {1, 2, 3, 4};
        System.out.println(reduce(data, (a, b) -> a + b));
    }
}

Интерфейс с тремя аргументами

JDK предоставляет интерфейсы только для одного и двух аргументов. Для трёх и более аргументов определите собственный интерфейс.

@FunctionalInterface
interface TriFunction<A, B, C, R> {
    R apply(A a, B b, C c);
}

public class Main {
    public static void main(String[] args) {
        TriFunction<Integer, Integer, Integer, Integer> sum3 = (a, b, c) -> a + b + c;
        System.out.println(sum3.apply(1, 2, 3));
    }
}

Ссылки на методы подходят для пользовательских интерфейсов

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

@FunctionalInterface
interface StringTest {
    boolean check(String s);
}

public class Main {
    public static void main(String[] args) {
        StringTest blank = String::isBlank;
        System.out.println(blank.check("   "));
    }
}

Анонимный класс и лямбда-выражение

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

@FunctionalInterface
interface Action {
    void run();
}

public class Main {
    public static void main(String[] args) {
        Action old = new Action() {
            public void run() { System.out.println("anonymous"); }
        };
        Action neo = () -> System.out.println("lambda");
        old.run();
        neo.run();
    }
}

Быстрая проверка

Что гарантирует @FunctionalInterface?

Повторение

Вы определяли собственные функциональные интерфейсы:

  • Функциональный интерфейс содержит ровно один абстрактный метод (SAM).
  • @FunctionalInterface обеспечивает соблюдение этого правила во время компиляции.
  • Методы по умолчанию и статические методы, обобщения и проверяемые исключения разрешены.
  • Пользовательские интерфейсы заполняют пробелы, которые не покрывает JDK, например функции с тремя аргументами или лямбда-выражения с проверяемыми исключениями.

Часто задаваемые вопросы

Урок «Пользовательские функциональные интерфейсы» бесплатный?

Да — полный текст урока «Пользовательские функциональные интерфейсы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.

Чему я научусь в уроке «Пользовательские функциональные интерфейсы»?

Создавайте собственные интерфейсы с @FunctionalInterface Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Java Academy?

Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Пользовательские функциональные интерфейсы»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Java Academy?

Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Function и BiFunction
  2. Supplier и Consumer
  3. Predicate и композиция
  4. Пользовательские функциональные интерфейсы
← Назад к Java Academy