Можно ли объявлять дефолтные методы в функциональном интерфейсе Java
Что проверяют
Знаете ли вы формальное определение функционального интерфейса, а не пересказ «интерфейс с одним методом». Следом спрашивают, что ещё не считается абстрактным методом и что будет при конфликте дефолтных методов из двух интерфейсов.
Как отвечать
Да, и сколько угодно. Функциональный интерфейс это интерфейс ровно с одним абстрактным методом, остальное не ограничено.
- не увеличивают счётчик:
default,static, а такжеprivateиprivate static(с Java 9); - методы
Object: публичные абстрактные объявленияequals,hashCode,toStringне считаются, реализация придёт отObject. Примерjava.util.Comparator: абстрактныйcompare, объявленныйequals, дефолтныеreversedиthenComparing, статическиеcomparingиnaturalOrder, и он остаётся функциональным; @FunctionalInterface: необязательная аннотация, включает проверку компилятора. Лямбда соберётся и без неё;- зачем они вообще: добавить метод в интерфейс, не сломав существующие реализации. Так
IterableполучилforEach, аCollectionполучилstreamиremoveIf.
Про лямбду отдельно: MyIface f = () -> ... реализует только абстрактный метод, дефолтные приходят готовыми. Переопределить дефолтный лямбдой нельзя, нужен анонимный класс.
Ограничения: дефолтный метод нельзя пометить final или synchronized и нельзя им переопределить методы Object. Если класс наследует два интерфейса с одинаковой сигнатурой дефолтного метода, конфликт надо разрешить явно: переопределить метод и позвать Iface1.super.method(). Порядок разрешения: реализация из класса бьёт интерфейс, более специфичный интерфейс бьёт более общий, иначе ошибка компиляции.
Где спотыкаются
Держат в голове «интерфейс с одним методом» и не могут объяснить, почему Comparator с двумя десятками методов подходит под лямбду.
Называют дефолтные методы множественным наследованием как в C++. Наследуется поведение, но не состояние: полей в интерфейсе нет, ромб разруливается правилами специфичности и явным X.super.
Путают default и static. Статический метод интерфейса не наследуется реализацией и не виден через экземпляр, звать его можно только как MyIface.helper().