Перейти к основному содержимому

Что такое опция –release в компиляторе Java 9?

· 5 мин. чтения

1. Обзор

В этом руководстве мы узнаем о новом параметре командной строки Java 9 –release. Компилятор Java, работающий с параметром –release N , автоматически генерирует файлы классов, совместимые с версией Java N. Мы обсудим, как этот параметр связан с существующими параметрами командной строки компилятора -source и -target.

2. Необходимость — вариант выпуска

Чтобы понять необходимость опции — Release , давайте рассмотрим сценарий, в котором нам нужно скомпилировать наш код с помощью Java 8 и мы хотим, чтобы скомпилированные классы были совместимы с Java 7.

До Java 9 этого можно было добиться с помощью параметров — source и — target , где

  • -source: указывает версию Java, принятую компилятором
  • -target: указывает версию Java файлов классов для создания

Предположим, что скомпилированная программа использует API-интерфейсы, доступные исключительно в текущей версии платформы, в нашем случае Java 8. В этом случае скомпилированная программа не может работать на более ранних версиях, таких как Java 7, независимо от значений, переданных в — источник и — целевые варианты.

Кроме того, нам нужно будет добавить опцию –bootclasspath вместе с –source и –target для работы в Java версии 8 и ниже.

Чтобы упростить эту проблему кросс-компиляции, в Java 9 была введена новая опция — выпуск для упрощения процесса.

3. Связь с опциями -source и -t target

Согласно определению JDK , –release N можно расширить следующим образом:

  • для N < 9, -source N -target N -bootclasspath <документированные-API-из-N>
  • для N >= 9, -source N -target N –system <документированные-API-из-N> ``

Вот несколько подробностей об этих внутренних опциях:

  • -bootclasspath: разделенный точкой с запятой список каталогов, архивов JAR и ZIP для поиска файлов классов загрузки
  • system : переопределяет расположение системных модулей для Java 9 и более поздних версий .

Кроме того, задокументированные API-интерфейсы находятся в $JDK_ROOT/lib/ct.sym , который представляет собой ZIP-файл, содержащий файлы классов, урезанные в соответствии с версией Java.

Для версии Java N< 9 эти API включают в себя классы начальной загрузки, полученные из jar-файлов, расположенных в jre/lib/rt.jar и других связанных jar-файлах.

Для версии Java N >= 9 эти API включают классы начальной загрузки, полученные из модулей Java, расположенных в каталоге jdkpath/jmods/ .

4. Использование с командной строкой

Во-первых, давайте создадим пример класса и воспользуемся переопределенным методом flip ByteBuffer , который был добавлен в Java 9:

import java.nio.ByteBuffer;

public class TestForRelease {

public static void main(String[] args) {
ByteBuffer bb = ByteBuffer.allocate(16);
bb.flip();
System.out.println("ForEach: --release option test is successful");
}
}

4.1. С существующими параметрами -source и -target

Давайте скомпилируем код в Java 9, используя значения параметров -source и -target равные 8:

/jdk9path/bin/javac TestForRelease.java -source 8 -target 8

Результат этого успешен, но с предупреждением:

warning: [options] bootstrap class path not set in conjunction with -source 8

1 warning

Теперь давайте запустим наш код на Java 8:

/jdk8path/bin/java TestForRelease

Мы видим, что это не удается:

Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;
at com.corejava.TestForRelease.main(TestForRelease.java:9)

Как мы видим, это не то, что мы ожидали увидеть с заданным значением 8 в наших опциях -release и -target . Поэтому, хотя компилятор должен это учитывать, это не так.

Давайте разберемся в этом подробнее.

В версиях до Java 9 класс Buffer содержал метод flip :

public Buffer flip() {
...
}

В Java 9 ByteBuffer, который расширяет Buffer, переопределяет метод flip :

@Override
public ByteBuffer flip() {
...
}

Когда этот новый метод компилируется на Java 9 и запускается на Java 8, мы получаем ошибку, поскольку оба метода имеют разные типы возвращаемых значений, а поиск метода с использованием дескриптора завершается ошибкой во время выполнения:

Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;
at com.corejava.TestForRelease.main(TestForRelease.java:9)

Во время компиляции мы получили предупреждение, которое раньше игнорировали. Это связано с тем, что компилятор Java по умолчанию компилирует последние версии API . Другими словами, компилятор использовал классы Java 9, несмотря на то, что мы указали –source и –target равными 8, поэтому наша программа не работала на Java 8.

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

Теперь давайте перекомпилируем тот же код с опцией –bootclasspath :

/jdk9path/bin/javac TestForRelease.java -source 8 -target 8 -Xbootclasspath ${jdk8path}/jre/lib/rt.jar

Опять же, результат успешен, и на этот раз у нас нет никаких предупреждений.

Теперь давайте запустим наш код на Java 8, и мы увидим, что это успешно:

/jdk8path/bin/java TestForRelease 
ForEach: --release option test is successful

Хотя теперь кросс-компиляция работает, нам пришлось предоставить три параметра командной строки.

4.2. С опцией –release

Теперь скомпилируем тот же код с опцией --release :

/jdk9path/bin/javac TestForRelease.java —-release 8

Опять же, на этот раз компиляция прошла успешно, без предупреждений.

Наконец, когда мы запускаем код на Java 8, мы видим, что он выполнен успешно:

/jdk8path/bin/java TestForRelease
ForEach: --release option test is successful

Мы видим, что с опцией --release все просто, поскольку javac внутри устанавливает правильные значения для -source, -target и --bootclasspath.

5. Использование с подключаемым модулем компилятора Maven

Обычно мы используем инструменты сборки, такие как Maven или Gradle, а не инструмент командной строки javac . Итак, в этом разделе мы увидим, как мы можем применить параметр –release в плагине компилятора maven.

Давайте сначала посмотрим, как мы используем существующие опции -source и -target :

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>

Вот как мы можем использовать опцию –release :

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>1.8</release>
</configuration>
</plugin>
</plugins>

Хотя поведение такое же, как мы описали ранее, способ передачи этих значений компилятору Java отличается.

6. Заключение

В этой статье мы узнали об опции –release и ее связи с существующими опциями –source и –target . Затем мы увидели, как использовать эту опцию в командной строке и с подключаемым модулем компилятора Maven.

Наконец, мы увидели, что новый вариант — выпуск требует меньше входных параметров для кросс-компиляции. По этой причине рекомендуется по возможности использовать его вместо параметров -target , -source и -bootclasspath .