Скомпилированы ли Java-выражения Java 8 обратно совместимы с более ранними версиями среды выполнения Java?

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

Важное соображение перед использованием Java 8 и lambdas в производственной среде заключается в том, может ли исполняемый код JDK8, который использует лямбда-выражения, выполнять в более ранней версии среды выполнения Java. Меня особенно интересуют JRE6 и JRE7 как целевые платформы.

Одна рука, я понимаю, что лямбды - это просто синтаксический сахар вокруг создания анонимного класса, содержащего один метод. С другой стороны, я не уверен, что эта эквивалентность подразумевает, что байт-код, сгенерированный для каждого, идентичен и/или совместим в версиях JVM, отличных от JRE8.

Например, с учетом интерфейса одного метода:

public interface Action<T> {
    public void perform(T argument);
}

Следующие два фрагмента являются "функционально" эквивалентными:

С лямбдой:

final Action<String> y = i -> System.out.println(i);

С анонимным экземпляром класса:

final Action<String> y = new Action<String>() {
    @Override
    public void perform(final String i) {
        System.out.println(i);
    }
};

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

Ответы

Ответ 1

В общем случае невозможно, чтобы Javac-компилятор использовал исходный уровень, который выше целевого уровня JVM. Таким образом, ответ НЕТ.

Ответ 2

Официально нет, но для неофициального решения вы должны посмотреть проект Retrolambda. Он не поддерживает изменения API Collection Collection, но он может обрабатывать выражения лямбда-выражения (и ссылки на методы) для вас.

Ответ 3

Я так не верю - версия байт-кода отличается (52, я думаю), и лямбда использует invokedynamic и не переводится в анонимные классы.

Ответ 4

Java 8 вводит новую концепцию реализации метода по умолчанию в интерфейсах. Эта возможность добавлена ​​для обратной совместимости, так что старые интерфейсы могут использоваться для использования возможностей ямбда-выражения Java 8. Например, "Интерфейс List или" Collection "не имеет объявления forEach. Таким образом, добавление такого метода просто нарушит реализацию структуры коллекции. Java 8 вводит метод по умолчанию, так что интерфейс List/Collection может иметь стандартную реализацию метода forEach, а класс, реализующий эти интерфейсы, не должен реализовывать то же самое.

public interface vehicle {
  default void print(){
      System.out.println("I am a vehicle!");
                       }
                          }