Пользовательские функциональные интерфейсы
Создавайте собственные интерфейсы с @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 — локальная установка не требуется.
Все уроки этого курса
- Function и BiFunction
- Supplier и Consumer
- Predicate и композиция
- Пользовательские функциональные интерфейсы