Подтвердить что ты не робот

Точное определение "функционального интерфейса" в Java 8

Недавно я начал изучать Java 8, и я не могу полностью понять концепцию "функционального интерфейса", которая необходима для реализации лямбда-выражений Java. В Java есть довольно подробное руководство по лямбда-функциям, но я застрял в главе, которая дает определение концепции функциональных интерфейсов. Определение гласит:

Точнее, функциональный интерфейс определяется как любой интерфейс, который имеет ровно один абстрактный метод.

Затем он переходит к примерам, одним из которых является интерфейс Comparator:

public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj);
} 

Я смог проверить, что вместо аргумента Comparator я могу использовать функцию лямбда, и она работает (например, Collections.sort(list, (a, b) → ab)).

Но в интерфейсе Comparator методы compare и equals являются абстрактными, что означает, что он имеет два абстрактных метода. Итак, как это может работать, если для определения требуется, чтобы интерфейс имел ровно один абстрактный метод? Что мне здесь не хватает?

4b9b3361

Ответ 1

Из той же страницы, с которой вы связались:

Компаратор интерфейса является функциональным, потому что, хотя он объявляет два абстрактных метода, один из этих-равно - имеет подпись, соответствующую общедоступному методу в объекте. Интерфейсы всегда объявляют абстрактные методы, соответствующие общедоступным методам Object, но они обычно делают это неявно. Неявно или явно объявлено, что такие методы исключаются из счета.

Я не могу сказать это лучше.

Изменить: Обновлен до последнего текста этой страницы, за комментарий Мориса (спасибо!)

Ответ 2

Другое объяснение приведено на странице @FunctionalInterface:

Концептуально функциональный интерфейс имеет ровно один абстрактный метод. Поскольку методы по умолчанию имеют реализацию, они не абстрактны. Если интерфейс объявляет абстрактный метод, переопределяющий один из общедоступных методов java.lang.Object, это также не учитывает счет абстрактного метода интерфейса, поскольку любая реализация интерфейса будет иметь реализацию из java.lang.Object или в другом месте.

Вы можете проверить, какой интерфейс является правильным функциональным интерфейсом, используя @FunctionalInterface.

например:.

  • это работает

    @FunctionalInterface
    public interface FunctionalInterf {
    
        void m();
    
        boolean equals(Object o);
    
    }
    
  • это порождает ошибку:

    @FunctionalInterface
    public interface FunctionalInterf {
    
        void m();
    
        boolean equals();
    
    }
    

    Несколько неперекрывающих абстрактных методов, найденных в интерфейсе FunctionalInterf

Ответ 3

Q. Но в интерфейсе Comparator методы compare() и equals() являются абстрактными, что означает, что он имеет два абстрактных метода. Итак, как это может работать, если для определения требуется, чтобы интерфейс имел ровно один абстрактный метод? Что мне здесь не хватает?

а.

Функциональный интерфейс может указывать любой общедоступный метод, определенный Объектом, такой как equals(), не влияя на его статус "функциональный интерфейс". Общедоступные методы объектов считаются неявными членов функционального интерфейса, поскольку они автоматически реализуются экземпляром функциональный интерфейс.

Ответ 4

Документы Java говорят:

Обратите внимание, что всегда безопасно не переопределять Object.equals(Object). Однако переопределение этого метода может в некоторых случаях улучшить производительности, позволяя программам определять, что два разных компараторы налагают один и тот же порядок.

Может быть, Компаратор особенный? Может быть, хотя это интерфейс, есть некоторая реализация по умолчанию equals(), которая вызывает compare()? Алгоритмически это тривиально.

Я думал, что все методы, объявленные в интерфейсах, были абстрактными (т.е. без реализации по умолчанию). Но, может быть, я что-то упустил.

Ответ 5

Определение:

Если интерфейс содержит только один абстрактный метод, то такой тип интерфейса называется функциональным интерфейсом.

Применение:

  • Как только мы напишем выражение Lambda "- > ", чтобы вызвать его функциональность, то в этом контексте нам нужен функциональный интерфейс.
  • Мы можем использовать ссылку на функциональный интерфейс для ссылки Lambda выражение.
  • Внутри функционального интерфейса мы можем иметь один абстрактный метод и n количество стандартных/статических методов.

Функциональный интерфейс по отношению к наследованию:

Если интерфейс расширяет функциональный интерфейс, а дочерний интерфейс не содержит абстрактного метода, тогда дочерний интерфейс также считается функциональным интерфейсом.

Функциональный интерфейс не является новым для java, который уже используется в следующих интерфейсных API:

  • Runnable: содержит только метод run().
  • Callable: содержит только метод call().
  • Сопоставимый: содержит метод compareTo().