Ответ
Основная цель: Обеспечение обратной совместимости при эволюции API, в частности, для библиотек коллекций (Collections Framework) и Stream API.
Проблема до Java 8: Интерфейс — это чистый контракт. Добавление нового метода в существующий интерфейс ломало все классы, которые его реализовывали, так как требовало немедленной реализации этого метода.
Решение в Java 8: default-методы (методы с реализацией по умолчанию) позволяют добавлять новую функциональность в интерфейсы, не нарушая работу существующего кода.
Классический пример — метод stream() в интерфейсе Collection:
public interface Collection<E> extends Iterable<E> {
// ... другие методы
// Новый метод, добавленный в Java 8. Все существующие реализации
// (ArrayList, HashSet и т.д.) автоматически его "получили".
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
}
// Старый код, написанный до Java 8, продолжает работать.
// Новый код может использовать stream() на любой коллекции.
List<String> list = Arrays.asList("a", "b", "c");
list.stream().forEach(System.out::println); // Работает!
Другие важные аспекты:
- Множественное наследование поведения: Класс может реализовывать несколько интерфейсов с
default-методами, что является формой множественного наследования в Java. - Разрешение конфликтов: Если класс реализует два интерфейса с одинаковыми
default-методами, он обязан переопределить этот метод, указав конкретную реализацию или выбрав одну из родительских с помощью синтаксисаInterfaceName.super.methodName().interface A { default void foo() { System.out.println("A"); } } interface B { default void foo() { System.out.println("B"); } } class C implements A, B { @Override public void foo() { A.super.foo(); // Явно указываем, какую реализацию использовать } } - Отличие от абстрактных классов:
default-методы не могут переопределять методыObject(например,toString,equals) и не могут содержать состояние (поля). Их задача — предоставлять поведение по умолчанию.