Java 9のその先へ~JavaOne Conference 2017レポート

第3回 Java 9のモジュール機能で何が変わるのか[JavaOne2017]

この記事を読むのに必要な時間:およそ 4 分

2017年9月にリリースされたJava 9にはさまざまな新機能が追加されていますが,中でもとりわけ影響度が大きいのがモジュール機能です。この機能の導入にともなって,JDK 9には旧バージョンとの互換性を伴わないいくつかの修正が加わっているからです。すなわち,既存のアプリケーションやライブラリがJava 9ではそのまま動かない可能性がある,ということです。

10月1日から5日の5日間に渡って開催されたJavaOne 2017でも,このモジュール機能は大きなトピックのひとつとして挙げられ,多くのセッションが開かれました。本レポートでは,それらのセッションで紹介された内容も踏まえながら,Java 9のモジュール機能についていま一度おさらいします。

モジュール機能の追加に至る紆余曲折

Javaへのモジュール機能の追加に関する議論がスタートしたのは10年以上も前のことになります。Javaアプリケーションの多様化やJava仕様そのものの巨大化によって,従来のパッケージの仕組みだけではクラスライブラリの適切な構造化や管理が難しくなったというのがその発端です。この問題は「Jar地獄」などと呼ばれ,Java 9のリリースに至るまで何度となく語られてきました。

さて,Javaのモジュール機能としては最初にJava SE 7に向けて2つのJSR(JSR 277とJSR 294)が提案されましたが,これらは実現には至りませんでした。その後,2009年にJava SEのスペックリードであるMark Reinhold氏が,モジュール機能の仕様化と実装を行うプロジェクトとしてProject Jigsawを立ち上げます。正式なJSRはJSR 376: Java Platform Module Systemです。

これが最終的にJava 9につながるわけですが,実際にはその道は非常に険しいものでした。結果としてJigsawは,Java SE 7および8のリリースには間に合わず,実に8年を経てようやくJava 9に含まれることになったわけです。これだけ時間がかかった理由はさまざまですが,最も大きな要因としては,Jigsawの影響範囲が極めて広く,既存のAPIやライブラリに大きく関係する変更だったからということが挙げられます。

Jigsawの仕様はこの8年の間に二転三転しています。Java 9リリースの直前にも,JCPでの最終投票がこのJigsawが原因となって一旦否決されており,細かな仕様の調整が行われました。したがって,Java 9のモジュール機能を使う場合には,必ず正式リリース以降の情報を参照することをお勧めします。

8年に渡る長い道のり 左がMark Reinhold氏

8年に渡る長い道のり 左がMark Reinhold氏

モジュール機能によってできること

Project Jigsawによって何ができるようになるかということは,OpenJDKのProject Jigsawのページに詳しく掲載されています。Jigsawは複数のJEP(JDK Enhancement Proposal)から構成されていますが,簡単にまとめると次のようなことができるようになるということです。

  • モジュール間の依存関係の明確化
  • モジュールの公開範囲の設定
  • バージョン設定
  • 標準ライブラリのモジュール化
  • 必要なモジュールのみを含むランタイムの作成

大雑把に言えば,複数のクラスをひとつのモジュールとしてまとめて,その公開範囲の設定や,バージョンの設定,モジュール間の依存関係の設定などを行うことができるということになります。そのうえで,標準ライブラリ自体もこの仕組みを使って複数のモジュールに分割し,依存関係や公開範囲が明確なるように作り直そうというわけです。つまり,標準ライブラリの構成がこれまでとはガラリと変わります。

たとえば,Java SEのコア部分のAPIは下図のような26個のモジュールに分割されました。矢印はモジュール間の依存関係を表しています。

Java SEのコアAPIのモジュール構成

Java SEのコアAPIのモジュール構成

JDK 9には上記の他に,Java SEのコアAPIに含まれないJDKのAPIを提供するモジュールや,Java FX関連のAPIを提供するモジュールなどが含まれています。これにともなって,JDKのAPIドキュメントもモジュール単位での閲覧ができるように修正されています。どのパッケージがどのモジュールに含まれているかなどはAPIドキュメントを参照してください。

最も基本的な事項のおさらい

それでは,まずは最も基本的な内容をおさらいしましょう。JavaOne 2017ではモジュール機能の基礎を扱うセッションが多数行われましたが,そのうち中からOracleのAlex Buckley氏によるセッション「Modular Development with JDK 9」で解説された内容を紹介します。

モジュールは,アプリケーションのルートディレクトリに配置するmodule-info.javaというファイルで定義します。モジュール定義に使用するおもなキーワードは以下の3つです。

  • module - モジュールの宣言をする
  • exports - 公開するパッケージを指定する
  • requires - 依存するモジュールを指定する

次の図のコードでは,hello.worldというモジュールを宣言しています。hello.worldモジュールはjava.baseモジュールに依存し,外部のすべてのモジュールに対してcom.example.helloパッケージを公開します。このサンプルではjava.baseモジュールを明示的にrequires指定していますが,実際にはjava.baseは全てのモジュールが暗黙的に依存するモジュールなので,requires宣言は省略することが可能です。

モジュール定義におけるexportsとrequires

モジュール定義におけるexportsとrequires

コンパイルは下図の右下のように,javacコマンドにmodule-info.javaを含める形で行います。この例では,com.example.helloパッケージのSayHello.javaクラスをコンパイルしています。もし依存するモジュールがある場合には,-pでそのモジュールのディレクトリのパスを指定します。

モジュール付きのコンパイル

モジュール付きのコンパイル

実行時には,javaコマンドに-pで必要なモジュールがあるディレクトリのパスを,-mでメインとなるモジュール名またはクラス名を指定します。この例では,モジュールのパスとしてmodsを,メインのモジュールとしてhello.worldが指定されています。hello.worldのexportsされたパッケージにはmain()メソッドが1つのみあるので,それが起動時に呼び出されるメソッドになります。

モジュールの実行

モジュールの実行

なお,モジュール化されたアプリケーションを実行する場合には,依存関係に関する次のようなルールがあります。

  • 依存するモジュールが足りない場合は実行できない
  • モジュールは循環依存になっていていはいけない(AとBがお互いに依存し合うなど)
  • 1つのパッケージが複数のモジュールにまたがってはいけない

著者プロフィール

杉山貴章(すぎやまたかあき)

有限会社オングス所属。Javaやシェルスクリプトによるソフトウェア開発を手がけるかたわら,プログラミング関連書籍やIT系雑誌記事,ニュース記事などの執筆などを行っている。著書に『正規表現書き方ドリル』(2010年,技術評論社),『図解クラウド 仕事で使える基本の知識』(2011年,技術評論社)などがある。

コメント

コメントの記入