Java 10の特徴
Java10はその23年の歴史の中で最も速いリリースとされています。Javaは成長と進化の遅さが批判されてきましたが、Java10はその概念を覆しました。Java10は多くの未来志向の変更を含むリリースであり、その範囲と影響は明白ではないかもしれませんが、遠大なものです。この記事では、Java10リリースに追加されたさまざまな機能について議論します。その前に、Javaリリースモデルに導入されたいくつかの変更について説明します。
長期サポートモデル
2017年から、オラクルとJavaコミュニティはJavaのリリースサイクルを6ヶ月に変更することを発表しました。オラクルJava SE製品は、Long Term Support(LTS)モデルに移行しました。これはどういう意味でしょうか?LTSバージョンの製品は、オラクルから優れたサポートと持続的なサポートを提供され、3年ごとにターゲットとされます。各Javaリリースは、1つまたは2つの主要な機能に基づいてモデル化され、これらの機能がリリースを進めます。障害があるとリリースが延期され、市場投入が遅れます。Java 9の主要な機能であるProject Jigsawは、何度かリリース日程を延期し、リリースが1.5年以上遅れました。6ヶ月サイクルのリリースでは、リリーストレインに従います。リリーストレインは、6ヶ月ごとにスケジュールが設定されます。選ばれた機能はトレインに乗りますが、そうでない場合は次のスケジュールされたトレインまで待つことになります。
オラクルJDKとオープンJDKの比較
開発者にとって使いやすいようにするため、オラクルとJavaコミュニティは、今後主要なJDKとしてOpenJDKバイナリを推進しています。これは以前の状況と比べると大きな救済です。以前はJDKバイナリはオラクルが所有権を持ち、ライセンス制約によってさまざまな制限がありました。しかし、オラクルは引き続き自社のJDKを開発し続ける予定ですが、長期サポートバージョンのみになります。これはクラウドやコンテナにも対応するための動きであり、オープンなJDKバイナリはコンテナの一部として配布することができます。それはどういう意味なのでしょうか? OpenJDKバイナリは毎6ヶ月ごとにリリースされますが、Oracle JDKバイナリは3年ごとにリリースされます(LTSバージョン)。どちらのJDKバイナリが採用されるのでしょうか?大きな組織はバージョン間の移行に時間がかかります。現在のバージョンにしがみつくことがあります。Java 6の業界採用率はJava 7よりも高く、業界は徐々にJava 8に移行しています。私の意見では、エンタープライズの間ではLTSバージョンが最も好まれるでしょう。ただし、Oracle JDKのLTSバージョンかオープンJDKのLTSバージョンかはまだ分かりません。それはクラウドの領域で多くの事が進行中だからです。Java 9と10は非LTSリリースです。2018年9月にリリース予定のJava 11はLTSリリースになります。
Java 10の機能
Java 10の利用可能な機能を覗いてみましょう。
- 時系列に基づくリリースのバージョニング(JEP 322)
時間ベースのリリースサイクルの採用により、OracleはJava SEプラットフォームとJDKのバージョン文字列スキーム、および関連するバージョン情報を、現在および将来の時間ベースのリリースモデルに対応するよう変更しました。新しいバージョン番号のパターンは次のようになります:$FEATURE.$INTERIM.$UPDATE.$PATCH。$FEATURE:カウンターは6か月ごとにインクリメントされ、フィーチャーリリースバージョンに基づいています(例:JDK 10、JDK 11)。$INTERIM:互換性のあるバグ修正および機能の強化を含む非フィーチャーリリースのためのカウンターですが、互換性のない変更は含まれません。通常、これはゼロのままです。6か月間に中間リリースはありません。これは将来のリリースモデルの改訂のために保持されます。$UPDATE:セキュリティの問題、リグレッション、新機能のバグを修正するための互換性のあるアップデートリリースのカウンターです。フィーチャーリリースの1か月後およびその後3か月ごとに更新されます。2018年4月のリリースはJDK 10.0.1です。7月のリリースはJDK 10.0.2です。およびその他。$PATCH:重大な問題を修正するための緊急リリースのカウンターです。これらのカウンター値をプログラムで取得するための新しいAPIも追加されています。以下、詳細を見てみましょう。
Version version = Runtime.version();
version.feature();
version.interim();
version.update();
version.patch();
さあ、バージョン情報を返すJavaランチャーを見てみましょう。
$ java -version
java version "10" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10+46)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)
バージョン番号の形式は「10」であり、ゼロ以外の他のカウンターは存在しません。リリース日付が追加されます。18.3は「2018年3月」のバージョン10の46番目のビルドとして読まれます。仮想的なJDK 10.0.1の93番目のビルドの場合、ビルドは10.0.1+939となります。### ローカル変数の型推論(JEP 286)
ローカル変数型推論は、Java 10の開発者にとって最も大きな新機能です。初期値を持つローカル変数の宣言に型推論を追加します。ローカル変数型推論は、以下のシナリオでのみ使用できます。
- Limited only to Local Variable with initializer
- Indexes of enhanced for loop or indexes
- Local declared in for loop
使用方法を見てみましょう。 (Shiyou houhou o mitemimashou.)
var numbers = List.of(1, 2, 3, 4, 5); // inferred value ArrayList<String>
// Index of Enhanced For Loop
for (var number : numbers) {
System.out.println(number);
}
// Local variable declared in a loop
for (var i = 0; i < numbers.size(); i++) {
System.out.println(numbers.get(i));
}
Java 10ローカル変数の型推論に関する当社独自の投稿で、さらに詳しく読むことができます。また、Javaベースの実験的なJITコンパイラ(JEP 317)についても詳細をお伝えします。
この機能により、JavaベースのJITコンパイラであるGraalをLinux/x64プラットフォーム上で実験的なJITコンパイラとして使用することが可能になります。これはJava 10の機能リストにおいて、間違いなく最も未来志向の含みであります。GraalはJava 9で導入されました。これまで使用していたJITコンパイラの代わりとして提供されるものであり、JVMへのプラグインです。つまり、JITコンパイラはJVMに依存せず、ダイナミックにプラグインとして接続および他のJVMCI準拠のプラグインと置換することができます。また、Javaの世界にAhead of Time(AOT)コンパイルをもたらします。また、ポリグロット言語の解釈もサポートしています。「Javaバイトコードをマシンコードに変換するためにJavaで書かれたJust in Timeコンパイラです」と混乱していますか?JVMがJavaで書かれているのであれば、JVMを実行するためにはJVMが必要ではありませんか?JVMはAOTでコンパイルされ、JITコンパイラはJVM内で使用され、ライブコード最適化を通じてパフォーマンスを向上させるために使用されます。GraalはJavaで完全にゼロからJITコンパイラを書き直したものです。以前のJITコンパイラはC++で書かれていました。これはあらゆるプログラミング言語の最終的な進化段階の1つとされています。Graalに切り替えるには、次のJVMパラメータを使用します:
-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler
クリス・シートンのプレゼンテーションからGraalに関する詳細を学ぶことができます。16番、アプリケーション・クラスデータ共有(JEP 310)について。
この機能は、スタートアップのフットプリントを改善し、既存のClass-Data Sharing(CDS)機能を拡張してアプリケーションクラスを共有アーカイブに配置するのに役立ちます。 JVMは起動時にいくつかの前提として、クラスをメモリに読み込むという手順を実行します。複数のクラスを含む複数のjarがある場合、最初のリクエストの遅延が明らかになります。これは、ブート時間が重要なサーバーレスアーキテクチャでは問題になります。アプリケーションの起動時間を短縮するために、アプリケーションのクラスデータ共有が使用されます。アイデアは、異なるJavaプロセス間で一般的なクラスのメタデータを共有してフットプリントを削減することです。これは次の3つのステップで実現できます:アーカイブするクラスの決定:共有アーカイブに含めるファイルのリストを作成するために、Javaランチャーを使用します。これは次のパラメータで実現できます:
$java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=hello.lst -cp hello.jar HelloWorld
アプリケーションCDS用のファイルリストのアーカイブを作成するために、Javaランチャーを使用します。次のパラメータに従って、これを達成することができます。
$java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=hello.lst -XX:SharedArchiveFile=hello.jsa -cp hello.jar
AppCDSアーカイブを使用する場合、以下のパラメータを持つJavaランチャーを使用してアプリケーションCDSを使用してください。
$java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa -cp hello.jar HelloWorld
- G1のためのパラレルフルGC(JEP 307)
JDK 9では、G1ガベージコレクタがデフォルトになりました。G1ガベージコレクタはフルガベージコレクションを回避しますが、収集のための並行スレッドがメモリを十分に素早く復活させることができない場合、ユーザーの体験に影響が出ます。この変更により、G1の最悪の遅延が改善され、フルガベージコレクションが並列に行われます。G1コレクタのマーク-スイープ-コンパクトアルゴリズムはこの変更の一環として並列化され、収集のための並行スレッドがメモリを十分に素早く復活させることができない場合にトリガーされます。25. ### ガベージコレクタインターフェース(JEP 304)
このJEPは将来志向の変更です。共通のガベージコレクターインターフェイスを導入することで、異なるガベージコレクターのコードの分離を改善します。この変更により、内部GCコードにより良いモジュラリティが提供されます。既存のコードベースを変更せずに新しいGCを追加する際に役立ち、以前のGCの削除またはメンテナンスにも役立ちます。26. 追加のUnicode言語タグ拡張(JEP 314)。
この機能は、java.util.Localeおよび関連するAPIを強化し、BCP 47言語タグの追加のUnicode拡張を実装します。Java SE 9では、サポートされているBCP 47 U言語タグの拡張は「ca」および「nu」です。このJEPでは、以下の追加の拡張のサポートが追加されます。
- cu (currency type)
- fw (first day of week)
- rg (region override)
- tz (time zone)
これらの追加拡張をサポートするために、様々なAPIに変更が加えられ、Uまたは追加拡張に基づいた情報が提供されるようになりました。
java.text.DateFormat::get*Instance
java.text.DateFormatSymbols::getInstance
java.text.DecimalFormatSymbols::getInstance
java.text.NumberFormat::get*Instance
java.time.format.DateTimeFormatter::localizedBy
java.time.format.DateTimeFormatterBuilder::getLocalizedDateTimePattern
java.time.format.DecimalStyle::of
java.time.temporal.WeekFields::of
java.util.Calendar::{getFirstDayOfWeek,getMinimalDaysInWeek}
java.util.Currency::getInstance
java.util.Locale::getDisplayName
java.util.spi.LocaleNameProvider
- ルート証明書(JEP 319)
OpenJDKを促進し、コミュニティユーザーに魅力的にするため、この機能ではJDKにデフォルトで一連のルート証明書機関(CA)証明書を提供します。これにより、OracleとOpenJDKのバイナリは機能的に同じになります。TLSなどの重要なセキュリティコンポーネントは、今後のOpenJDKビルドでデフォルトで動作します。JEP 312の###スレッドローカルハンドシェイクも含まれます。
これは、パフォーマンスを向上させるための内部のJVMの機能です。ハンドシェイク操作は、各Javaスレッドがセーフポイント状態にある間に実行されるコールバックです。このコールバックは、スレッド自体またはVMスレッドによって、スレッドをブロック状態にしたまま実行されます。この機能により、グローバルなVMセーフポイントを実行せずにスレッド上でコールバックを実行する方法が提供されます。個々のスレッドだけでなく、全てのスレッドまたはどれも行わないように、個別のスレッドを停止することが可能であり、かつ手軽に行えるようになります。31. ### 代替メモリデバイス上のヒープ割り当て(JEP 316)
アプリケーションはメモリを大量に消費し、クラウドネイティブアプリケーション、インメモリデータベース、ストリーミングアプリケーションの増加が見られます。これらのサービスに対応するために、さまざまなメモリアーキテクチャが利用可能です。この機能により、HotSpot VMはユーザーが指定したNV-DIMMなどの代替メモリデバイスに対して、Javaオブジェクトヒープの割り当てを向上させることができます。このJEPは、DRAMと同じセマンティクス(アトミック操作を含む)を持つ代替メモリデバイスを対象としており、既存のアプリケーションコードを変更することなくオブジェクトヒープのDRAMの代わりに使用することができます。32. ネイティブヘッダジェネレーションツールであるjavahを削除します(JEP 313)。
これはJDKからjavahツールを削除するための家政優れた変更です。このツールの機能は、JDK 8の一部であるjavacに追加されており、コンパイル時にネイティブヘッダーファイルを作成する能力を提供しているため、javahは不要になりました。 JDK Forestを単一のリポジトリに統合する JEP 296を実施します。
数年にわたり、JDKコードベースには様々なマーキュリアルリポジトリが存在してきました。異なるリポジトリは何らかの利点を提供していますが、さまざまな運用上の不都合もあります。この変更の一環として、JDKフォレストの多くのリポジトリが1つのリポジトリに統合され、開発を簡素化し効率化するための取り組みが行われました。36. ### APIの変更
Java 10では、APIが追加されたり削除されたりしました(タイプミスではありません)。Java 9では、将来のリリースで削除される予定のある特定のAPIに改良が加えられました。削除されたAPIはこちらで確認できます。追加されたAPIは73個あり、Java 10に追加されました。追加されたAPIは、比較を含めてこちらで確認できます。いくつかの追加機能を見てみましょう。
- List, Map & Set Interfaces are added with a static copyOf(Collection) method. Its returns an unmodifiable List, Map or Set containing the entries provided. For a List, if the given List is subsequently modified, the returned List will not reflect such modifications.
- Optional & its primitive variations get a method orElseThrow(). This is exactly same as get(), however the java doc states that it is a preferred alternative then get()
- Collectors class gets various methods for collecting unmodifiable collections (Set, List, Map)
List<String> actors = new ArrayList<>();
actors.add("Jack Nicholson");
actors.add("Marlon Brando");
System.out.println(actors); // prints [Jack Nicholson, Marlon Brando]
// New API added - Creates an UnModifiable List from a List.
List<String> copyOfActors = List.copyOf(actors);
System.out.println(copyOfActors); // prints [Jack Nicholson, Marlon Brando]
// copyOfActors.add("Robert De Niro"); Will generate an
// UnsupportedOperationException
actors.add("Robert De Niro");
System.out.println(actors);// prints [Jack Nicholson, Marlon Brando, Robert De Niro]
System.out.println(copyOfActors); // prints [Jack Nicholson, Marlon Brando]
String str = "";
Optional<String> name = Optional.ofNullable(str);
// New API added - is preferred option then get() method
name.orElseThrow(); // same as name.get()
// New API added - Collectors.toUnmodifiableList
List<String> collect = actors.stream().collect(Collectors.toUnmodifiableList());
// collect.add("Tom Hanks"); // Will generate an
// UnsupportedOperationException
結論
この記事では、Java 10の異なる新機能の追加について説明しました。もし大切な情報が見落とされていると思われる場合は、コメントでお知らせください。通常通り、こちらからGitHubで完全なコードを確認することもできます。