目次
Java9の新機能
2017年7月にリリースされたJava9では、次の新機能が追加されました。
- JShell (対話的にJavaコード実行するツール)
- 不変List/Set/Map用のファクトリメソッド
- Optionalクラスの拡張
- Stream APIの機能強化
- 並行処理のアップデート
- try-with-resourceの改善
- 並列処理の改善(スピン・ウェイト・ヒント)
- 変数ハンドル
- Process APIの改善
- Interface内のprivateメソッド
- モジュールシステム
- CompletableFuture APIの改善
- リアクティブストリーム
- 匿名クラスでのダイアモンド演算子
- @Deprecatedアノテーションの強化
- Multi-Resolution Image API
本記事では、追加された新機能の中から、JShellとモジュールシステムの使い方を紹介します。
JShellでJavaをスクリプト実行
JShellは、JavaのREPL環境で、コマンドラインでJavaのコードを対話形式で実行できます。JavaのAPIなどのちょっとした確認に使えます。
使用方法は、コマンドプロンプトを立ち上げ、「jshell」と入力しREPL環境を起動するだけです。
$ jshell | JShellへようこそ -- バージョン11.0.1 | 概要については、次を入力してください: /help intro jshell> System.out.println("Heelo World!") Heelo World!
モジュールシステムでパッケージのアクセス制御
モジュールとはJavaのパッケージやリソースをモジュールという単位にまとめたものです。モジュールが、他のモジュールをどのように使うか、どのパッケージを他のモジュールから見えるようにするのかを制御する仕組みです。
具体的には、「module-info.java」というJavaのファイルに、モジュール間のアクセス制御を記述します。
モジュールでできること
Javaのモジュールシステムによって、できる事を次のリストにまとめました。
- モジュール間の依存関係の明確化
- モジュールの公開範囲の設定
- バージョン管理
- 指定したモジュールのみを含むランタイムの作成
これまでのJavaでは、クラスをpublicにすると、他のパッケージやライブラリからも参照可能になってしまいます。
ライブラリなどを開発する際、内部利用のみを想定したクラスを作ることがあります。そのような内部クラスでも、ライブラリ内の他のパッケージから参照する場合、内部利用であってもpublicにせざる負えません。
クラスをpublicにすると、当然ライブラリ外からも参照できるようになり、意図しないクラスが使用される恐れがあり、これまでは「これは内部クラスです、使用しないで下さい」のように、JavaDocで、ただ注意喚起するしかありませんでした。
Java9から導入されたモジュールは、パッケージの上位階層になるもので、パッケージ単位にクラスを公開する/しないのアクセス制御ができるようになりました。この、モジュールのアクセス制御により、明確に内部クラスの利用を制限できるようになりました。
jar地獄からの開放
これまでのjarファイルは、クラスやリソースをまとめたファイルに過ぎず、jarファイルが必要とするライブラリなどの依存関係がパッと見わからず、jarファイル中のクラスを解析するか、とりあえずjarファイルを組み込んで「ClassNotFoundException」が出るたびに、必要なライブラリを組み込んでいくしか方法がありませんでした。
この依存関係を解決する作業は、参照するjarファイル数が増えると共に複雑化し、Javaの世界では、しばしば「jar地獄」と呼ばれています。
Java9から導入されたモジュールは、モジュールの定義を含めてjarファイルを作成することで、外部に依存しているモジュールや、そのバージョンを公開できます。これにより、これまで大変だったjarファイル間の依存関係の解決が、容易にできるようになりました。
パッケージをモジュール化する
自分で作成したJavaアプリをモジュール化して、パッケージのアクセス制御をする例を紹介します。
今回は、次のような階層のJavaのアプリをモジュール化する例で解説します。
src ├ com │ └ example │ ├ api │ │ ├ UserApi.java │ │ └ ProductApi.java │ └ internal │ └ Util.java └ module-info.java
「com.example.api」パッケージは、外部に公開する為のAPIクラスであり、「com.example.internal」パッケージは、内部でのみ利用するクラスで、スコープはpublicですが、外部には公開したくないクラスです。
アプリをモジュール化するためには、ソースのトップレベルの階層に「module-info.java」というファイルを作成します。
そして「module-info.java」には、次のような内容を記述します。
module my.service { exports com.example.api; requires java.logging; }
各行の内容について解説します。
▪️ 1行目
モジュールの宣言を行なっています。moduleキーワードの隣には、任意のモジュール名を書きます。
▪️ 2行目
exportsキーワードで「com.example.api」パッケージを外部に公開する宣言を行なっています。
▪️ 3行目
このモジュールが依存している、外部のモジュール名を指定しています。今回のアプリはログ出力のために、「java.logging」モジュールを使用してると仮定しています。
上記のような「module-info.java」を用意した状態で、jarファイルを作成すれば、使用して欲しくない「com.example.internal」パッケージは、外部からは参照できなくなります。
Java9移行時の注意点
Java8以前のバージョンから、Java9 に移行する時は、以下のような注意点があります。
▪️ Java EEのAPIが非推奨になった
corbaなどの、Java EEに由来するモジュールはJava9から非推奨になりました。
- java.activation
- java.corba
- java.transaction
- java.xml.bind
- java.xml.ws
- java.xml.ws.annotation
▪️ JDKの内部クラスが参照できなくなった
「sun.security」パッケージなどの、JDK内部でのみ利用が想定されていたパッケージが、Java9からは参照できなくなりました。
Java9のサポート状況
2019年10月時点のJava9のサポート状況ですか、Oracle JDKサポート期限が2018年3月までとなっており、すでにサポートは終了しています。また、Java9は有償での長期サポート(LTS)が設定されていません。
セキュリティが必要なシステムで利用する場合は、商用利用時は有償となりますが、サポート期限が2023年9月までのJava11を使うようにしましょう。Java11でも今回紹介したJava9の新異能は使用可能です。
Java9では意外なものが非推奨に
Java9では、Java8以前でよく使われている、コンストラクタで値を指定して初期化するコードが、非推奨になりました。
Integer i = new Integer(100);
実際に上のコードを、Java9以降のコンパイラでビルドすると、次のような警告メッセージが出力されます。また、Integerに限らず、Double、Float、Longなどについても同様に非推奨になっています。
コンストラクター Integer(int) は使用すべきではありません。
Java9以降では、次のようにvalueOfメソッドを使う書き方が推奨されているため、これからはvalueOfを使って値の初期化を行いましょう。
Integer i = Integer.valueOf(100);
valueOfメソッドを使った値の初期化は、Java5 (Java1.5)から使えるため、今現在Java8などで開発している場合も、今後コンストラクタで値を初期化する方法が非推奨になることを考えて、積極的にvalueOfメソッドを使っていきましょう。
Javaの非推奨APIは、次のページで確認することができます。
非推奨のAPI
まとめ
Java9で追加された新機能と、Java9の目玉機能でもあるモジュールについて詳しく解説していきました。また、2017年9月にリリースされたJava9からは、6ヶ月ごとにフィーチャーリリースが行われるようにリリースモデルに変更されました。
Java8で追加されたstreamのように、新しい機能により、これまでは煩雑になりがちだったコードが、簡潔に書けるようになる変更も行われることもあるため、新しいJavaがリリースされた際は、どんな新機能があるかチェックするようにしましょう。
CORBAはJava11で機能が削除されました。