Методы Java 8 по умолчанию нарушают совместимость источников?

обычно это был случай, когда исходный код Java был вперед совместим. До Java 8, насколько я знаю, оба скомпилированные классы и Источник были совместимыми с Позже с JDK/JVM в релизы. [Update: это неправильно, см. комментарии re 'enum' и т. д. Ниже.] Однако с добавлением методов по умолчанию в Java 8 это больше не так.

например, библиотека, которую я использую и реализацией java.util.List который включает в себя List<V> sort(). Этот метод возвращает копию содержимого отсортированного списка. Эта библиотека, развернутая как зависимость файла jar, отлично работала в проекте, построенном с использованием JDK 1.8.

однако позже мне пришлось перекомпилировать саму библиотеку с помощью JDK 1.8 и Я обнаружил, что библиотека больше не компилируется:List-реализация класса с собственным sort() метод теперь конфликтует с Java 8 java.util.List.sort() метод по умолчанию. В Java 8 sort() метод по умолчанию сортирует список на месте (возвращает void); метод-поскольку он возвращает новый отсортированный список - имеет несовместимую подпись.

Итак, мой основной вопрос:

  • не вводит ли JDK 1.8 прямую несовместимость для исходного кода Java из-за методов по умолчанию?

также:

  • это первое такое прямое несовместимое изменение?
  • это рассматривалось или обсуждалось, когда методы по умолчанию, где разработан и реализован? Это где-нибудь задокументировано?
  • была (правда мелкие) неудобства со скидкой против выгоды?

ниже приведен пример кода, который компилируется и выполняется под 1.7 и работает под 1.8 - но не компилируется под 1.8:

import java.util.*;

public final class Sort8 {

    public static void main(String[] args) {
        SortableList<String> l = new SortableList<String>(Arrays.asList(args));
        System.out.println("unsorted: "+l);
        SortableList<String> s = l.sort(Collections.reverseOrder());
        System.out.println("sorted  : "+s);
    }

    public static class SortableList<V> extends ArrayList<V> {

        public SortableList() { super(); }
        public SortableList(Collection<? extends V> col) { super(col); }

        public SortableList<V> sort(Comparator<? super V> cmp) {
            SortableList<V> l = new SortableList<V>();
            l.addAll(this);
            Collections.sort(l, cmp);
            return l;
        }

    }

}

ниже показано, что этот код компилируется (или не выполняется) и запускается.

> c:toolsjdk1.7.0_10binjavac Sort8.java

> c:toolsjdk1.7.0_10binjava Sort8 this is a test
unsorted: [this, is, a, test]
sorted  : [this, test, is, a]

> c:toolsjdk1.8.0_05binjava Sort8 this is a test
unsorted: [this, is, a, test]
sorted  : [this, test, is, a]

> del Sort8*.class

> c:toolsjdk1.8.0_05binjavac Sort8.java
Sort8.java:46: error: sort(Comparator<? super V>) in SortableList cannot implement sort(Comparator<? super E>) in List
                public SortableList<V> sort(Comparator<? super V> cmp) {
                                       ^
  return type SortableList<V> is not compatible with void
  where V,E are type-variables:
    V extends Object declared in class SortableList
    E extends Object declared in interface List
1 error

5 ответов


разве JDK 1.8 не вводит прямую несовместимость для исходного кода Java из-за методов по умолчанию?

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

это первое такое прямое несовместимое изменение?

почти наверняка нет, так как мы подклассы классов из стандартной библиотеки с Java 1.0.

это рассматривалось или обсуждалось при разработке и реализации методов по умолчанию? Это где-нибудь задокументировано?

Да, это считалось. Увидеть Брайана Гетца августа 2010 бумага интерфейс" эволюция с помощью методов "общественного защитника":

  1. источник совместимости

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

был (правда, небольшой) дискомфорт, скидки и льготы?

раньше изменение интерфейса было бы наверняка нарушить совместимость. Теперь это может. Переход от "определенно" к "возможно" можно рассматривать либо положительно, либо отрицательно. С одной стороны, это делает возможным добавление методов к интерфейсам. С другой стороны, это открывает дверь к несовместимость вы видели не только с классами, но и с интерфейсами тоже.

преимущества больше, чем неудобства, хотя, как указано в верхней части статьи Гетца:

    сообщении

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

добавление замыканий на язык Java в JDK 7 создает дополнительный стресс для интерфейсов устаревающей коллекции; одним из наиболее значительных преимуществ замыканий является то, что оно позволяет разрабатывать более мощные библиотеки. Было бы разочарованием добавить языковую функцию, которая позволяет улучшить библиотеки, в то же время не расширяя основные библиотеки, чтобы воспользоваться этой функцией.


разве JDK 1.8 не вводит прямую несовместимость для исходного кода Java из-за методов по умолчанию?

да как вы видели себя.

это первое такое прямое несовместимое изменение?

нет. Java 5 enumключевое слово также было нарушено, потому что до этого у вас могли быть переменные с именем, которые больше не будут компилироваться в Java 5+

это рассматривалось или обсуждалось при дефолте методы где разработаны и реализованы? Это где-нибудь задокументировано?

да Orcale Java 8 Описание несовместимости источника

был (правда, небольшой) дискомфорт, скидки и льготы?

да


мы можем провести параллель с абстрактным классом. Абстрактный класс предназначен для подклассов, так что абстрактные методы могут быть реализованы. Сам абстрактный класс содержит конкретные методы, которые вызывают абстрактные методы. Абстрактный класс может развиваться, добавляя более конкретные методы; и эта практика может разбить подклассы.

поэтому точная проблема, которую вы описали, существовала еще до Java8. Проблема гораздо больше проявляется в API коллекции, потому что в дикой природе много подклассов.

List.sort является абсолютно необходимым. Я думаю, это спорно.

независимо от того, почему метод по умолчанию был введен в 1-м месте, теперь это отличный инструмент для дизайнеров API, и мы должны относиться к нему так же, как к конкретным методам в абстрактных классах - они должны быть тщательно разработаны заранее; и новые должны быть введены с большой осторожностью.


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

конфликты, как sort способ может возникнуть. Что-то, чтобы заплатить за дополнительную функциональность. В вашем случае также есть что исследовать (следует ли вместо этого использовать новую функциональность?).

совместимость Java вперед перерывов мало, больше в его системе набора текста, которая постоянно расширялась. Сначала с универсальными типами, а теперь с выводимыми типами из функциональных интерфейсов. От версии к версии и от компилятора к компилятору были небольшие различия.


читая этот вопрос, я думал о его решении.
методы по умолчанию решили проблемы обратной совместимости, но проблемы прямой совместимости будут существовать.
Я думаю, что вместо расширения существующих классов в таких случаях мы можем иметь наши интерфейсы приложения, чтобы добавить желаемое поведение в наш класс. Мы можем реализовать этот интерфейс конкретного приложения и использовать его.