Интерфейсы, часть 2: методы по умолчанию



Когда готовила материал по дефолтным методам, то перечитала почти все переписки разработчиков этой фичи. Огромное удовольствие — следить за спором опытных людей с высокой инженерной культурой и мощными теоретическими знаниями. Профессионализм завораживает🥰



Но я расскажу вам итог. В java 8 появилась новая возможность — методы с заданной реализацией:



interface Adapter {

default int get() {…}

}



Класс, который реализует интерфейс, переопределяет такой метод при необходимости.



Зачем?



1️⃣ Облегчить изменения API



Во времена java 7 в интерфейсах были только определения методов:



interface Collection<Т> {

void add(Т);

Т get();

}



Чтобы добавить, удалить или поменять сигнатуру метода нужно одновременно поменять код и в интерфейсе, и во всех реализациях. Если всё в рамках одного проекта, то проблем нет. Но если мы пишем библиотеку, то задача усложняется. Пользователи могут столкнутся с проблемами совместимости при переходе на новую версию.



Задача дефолтных методов — сгладить этот процесс, предоставить приемлемую или временную альтернативу. В JDK основная цель дефолтных методов — поддержка Stream API в коллекциях.



2️⃣ Вспомогательные методы



Которые не входят в прямую функциональность интерфейса, но их удобно добавить сюда, а не в каждый класс реализации. Нарушается принцип Interface segregation и часто похоже на костыль. Не одобряю, но такое встречается🙂



3️⃣ Комбинации базовых методов



Мы обсуждали это в прошлом посте. В интерфейсе есть методы, которые по сути — комбинация других методов этого же интерфейса.



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



Пример: интерфейс Comparator



Цепочка из 2 компараторов — это 2 вызова compare и объединение результатов. Логика всегда одинакова, и нет смысла дублировать её в каждом подклассе:



default Comparator thenComparing(Comparator) {…};



Что если класс реализует 2 интерфейса с методами по умолчанию?



Правила такие:

🔸 Если в классе переопределён метод по умолчанию — используется метод класса

🔸 Если один интерфейс наследуется от другого — используется метод наследника

🔸 В остальных случаях — ошибка компиляции



Отсюда ответы на вопросы перед постом:

1️⃣ Ошибка компиляции

2️⃣ Напечатается В