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
.