Java SE 9 の javac で過去バージョンをターゲットにするときには --release オプションを使用すると良い
JDK の javac コマンドを使って過去バージョンの Java 言語で書かれたソースコードをコンパイルする際には、-source オプションや -target オプションを使用してきました。 (JDK 8 までの話。) このとき、適切なブートストラップクラスパスを設定しなければ、対象バージョンに存在しない Java API を使用していてもビルドが通ってしまう、という問題がありました。
JDK 9 の javac コマンドには --release オプションが追加されました。 今後は (基本的には) このオプションを使用するようにすると良さそうです。
- ドキュメント : javac
Java SE 9 (Oracle JDK 9) のマイグレーションガイドより
マイグレーションガイドには以下のように書かれています。
If you use the
-sourceand-targetoptions withjavac, then check the values that you use. In JDK 9,javacuses a "one plus three back" policy of supporting-sourceand-targetoptions.The supported
-source/-targetvalues are 9 (the default), 8, 7, and 6 (6 is deprecated, and a warning is displayed when this value is used).In JDK 8,
-sourceand-targetvalues of 1.5/5 and earlier were deprecated and caused a warning to be generated. In JDK 9, those values cause an error.>javac -source 5 -target 5 Sample.java warning: [options] bootstrap class path not set in conjunction with -source 1.5 error: Source option 1.5 is no longer supported. Use 1.6 or later. error: Target option 1.5 is no longer supported. Use 1.6 or later.If possible, use the new
--releaseflag instead of the-sourceand-targetoptions. The--release Nflag is conceptually a macro for:-source N -target N -bootclasspath $PATH_TO_rt.jar_FOR_RELEASE_NThe valid arguments for the
--releaseflag follow the same policy as for-sourceand-target, one plus three back.javac can recognize and process class files of all previous JDKs, going all the way back to JDK 1.0.2 class files.
See JEP 182: Policy for Retiring
Java Platform, Standard Edition Oracle JDK 9 Migration Guide, Release 9javac-sourceand-targetOptions.
つまり、--release フラグを指定すると、-source オプションと -target オプションを指定し、さらに適切なブートクラスパスの指定も行った状態になります。 これまで、過去バージョンのブートクラスパスを設定するには、過去バージョンの Java 実行環境を取得してその中の rt.jar を指定してやる必要があったので、格段に便利になりました。
試してみた
実際に、以下のようなコードを含む Java のソースファイルをコンパイルしてみました。
public class Main { public static void main(String[] args) { String test = String.join("", ""); // Java SE 8 で Java API に導入されたメソッド。 } }
--release 8 を指定した場合は、問題なくコンパイルされます。
~\java-project> javac --release 8 .\Main.java
--release 7 を指定した場合は、下記のようにエラーになります。
~\java-project> javac --release 7 .\Main.java
.\Main.java:3: エラー: シンボルを見つけられません
String test = String.join("", "");
^
シンボル: メソッド join(String,String)
場所: クラス String
エラー1個Java 7 向けにビルドしたけど Java 7 の実行環境で動かすと (Java 7 にない API を使っていて) 例外が発生する、というようなミスが減りそうで最高ですね!
Gradle での使い方
Gradle 4.2.1 現在、JavaCompile タスクで javac の --release オプションを指定する方法として特別なメソッドは提供されていません。 通常のコンパイラオプションを指定する方法は使用できるので、通常のコンパイラオプションの指定と同じ方法で --release オプションを指定します。
具体的には CompileOptions#compilerArgs プロパティを使用します。 このドキュメントを読むと、『For example, it is possible to pass the --release option of JDK 9』 とか 『Note that if --release is added then -target and -source are ignored.』 とか書かれています。 --release オプションにもばっちり対応されていますね。
超単純な build.gradle の例を書いておきます。
apply plugin: 'java' tasks.withType(JavaCompile) { options.compilerArgs.addAll(['--release', '8']) }