Раньше interface не имел реализации и нам приходилось реализовывать абстрактные классы. Но сейчас, а конкретно, начиная с 'Java8', interface может иметь реализацию. Зачем так поступили? В чём здесь выигрыш? Какие преимущества дает интерфейс, имеющий реализацию? И главное, в чем тогда смысл использования абстрактных классов, если интерфейс может содержать реализацию методов?
Ответ
Интерфейс описывает только поведение (методы) и не может иметь состояние (поля), абстрактный класс - может.
В случае с default-методами, поведение может быть не только описано, но и реализовано. Однако по-прежнему без доступа к состоянию.
В Java 8 default-методы были добавлены во многом ради Stream API. Это позволило добавить методы spliterator() и stream() всем коллекциям, которые были написаны до появления Stream API, не затрагивая их реализации:
public interface Iterable
default Spliterator
public interface Collection
@Override
default Spliterator
default Stream
Как видите, default-методы тут ведут себя как миксины, оборачивающие некоторую стороннюю реализацию (Spliterators, StreamSupport) и превращающую ее в честные методы коллекций.
Пример из жизни. Есть интерфейс доступа к данным, который может иметь разные реализации:
public interface Repository {
Foo getFooWithTimeout(int id, int timeout);
// ...
}
И хочется иметь его сокращенную версию какого-то метода со значениями параметров по-умолчанию. Тогда достаточно просто обернуть существующий метод default-методом:
public interface Repository {
Foo getFooWithTimeout(int id, int timeout);
default Foo getFoo(int id) {
return getFooWithTimeout(id, 0);
}
// ...
}
Мы расширили контракт всех реализаций интерфейса Repository новым методом, при этом никто не пострадал нам не пришлось вторгаться в реализации.