Сколько методов может быть в функциональном интерфейсе?
Комментарии (3)
Ответ сгенерирован нейросетью и может содержать ошибки
Функциональные интерфейсы в Java
Ключевой принцип функционального интерфейса в Java (с версии 8+) заключается в том, что он должен содержать ровно один абстрактный метод. Это единственное требование, определённое спецификацией языка для того, чтобы интерфейс можно было использовать в качестве целевого типа для лямбда-выражения или ссылки на метод.
Сколько методов должно быть?
- Обязательно один абстрактный метод. Это его "функциональный дескриптор".
- При этом может быть любое количество
default-методов иstatic-методов. Они имеют реализацию внутри самого интерфейса и не нарушают правило "одного абстрактного метода". - Могут быть методы, унаследованные от
java.lang.Object. Компилятор Java не считает их абстрактными для целей функционального интерфейса, так как их реализация уже существует в Object.
Пример и пояснение
Рассмотрим стандартный функциональный интерфейс Predicate<T>:
@FunctionalInterface
public interface Predicate<T> {
// Единственный абстрактный метод (SAM - Single Abstract Method)
boolean test(T t);
// default-методы (их может быть много)
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
// static-метод (их тоже может быть много)
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
В этом интерфейсе:
test(T t)— единственный абстрактный метод.and,negate,or— триdefault-метода с готовой реализацией.isEqual—static-метод.
Аннотация @FunctionalInterface
Эта аннотация не делает интерфейс функциональным, а выполняет роль строгой проверки на этапе компиляции. Если мы пометим интерфейс этой аннотацией, но объявим в нём более одного абстрактного метода, компилятор выдаст ошибку.
@FunctionalInterface
interface MyFunctionalInterface {
void execute(); // OK
// void anotherAbstractMethod(); // ОШИБКА КОМПИЛЯЦИИ!
// Аннотация @FunctionalInterface не позволит это скомпилировать.
}
Важные исключения и нюансы
-
Методы
java.lang.Object: Абстрактные методы, которые являются переобъявлениями публичных методовjava.lang.Object(например,equals,hashCode,toString), не учитываются при подсчёте. Поэтому следующий интерфейс по-прежнему является функциональным:@FunctionalInterface interface ComplexFunctionalInterface { void doWork(); boolean equals(Object obj); // Не считается за "лишний" абстрактный метод String toString(); // Не считается } -
Интерфейс без методов? Нет, интерфейс без абстрактных методов (даже если в нём есть
defaultилиstaticметоды) НЕ является функциональным. Ему нечего будет реализовывать с помощью лямбды. -
Интерфейс с двумя абстрактными методами (без учёта методов Object) не является функциональным и не может быть использован с лямбда-выражениями.
Вывод
Таким образом, в функциональном интерфейсе может и должен быть ровно один абстрактный метод (SAM). При этом общее количество методов в нём может быть практически любым, так как к одному абстрактному методу можно добавлять неограниченное количество default- и static-методов, а также неограниченно переобъявлять методы из Object. Это ограничение "одного абстрактного метода" — фундаментальная концепция, лежащая в основе всей системы функционального программирования, добавленной в Java 8, и позволяющая использовать краткий синтаксис лямбда-выражений ((args) -> body).