注目記事

【Javaコード入門】オブジェクト指向構文_⑫モジュール

モジュールとは、パッケージを束ねるための単位です。Java 9で追加されました。 モジュールを利用することで、配下のパッケージに対するアクセス権限をより細かに設定できるようになります。具体的には、

  • 現在のモジュールの中でだけpublic
  • 特定のモジュールに対してだけpublic
  • すべてのモジュールに対してpublic

なパッケージを設定できます。たとえばライブラリをモジュールで束ねることで、そのライブラリの中でだけ利用しているパッケージが、不用意に他のコードからアクセスされることがなくなります(*)。

*)従来のJavaでは、ライブラリ内部でのみ利用するパッケージを不可視にする手段はありませんでした。パッケージプライベートよりも緩い権限が、すぐさま「すべてに対してpublic」だったからです。

標準ライブラリもモジュール

Java 9以降では、標準ライブラリもすべてモジュール化されています。具体的には、コマンドラインから以下のコマンドで確認できます。

> cd C:\jdk-23.0.1\bin
> java --list-modules
java.base@23.0.1
java.compiler@23.0.1
java.datatransfer@23.0.1
java.desktop@23.0.1
java.instrument@23.0.1
java.logging@23.0.1
java.management@23.0.1
java.management.rmi@23.0.1
java.naming@23.0.1
java.net.http@23.0.1
...中略...
jdk.naming.rmi@23.0.1
jdk.net@23.0.1
jdk.nio.mapmode@23.0.1
jdk.sctp@23.0.1
jdk.security.auth@23.0.1
jdk.security.jgss@23.0.1
jdk.unsupported@23.0.1
jdk.unsupported.desktop@23.0.1
jdk.xml.dom@23.0.1
jdk.zipfs@23.0.1

それぞれのパッケージ(クラス)が属するモジュールは、APIリファレンスからも確認できます。

▲現在のクラスが属するモジュールを確認

モジュールの基本

モジュールを定義するには、ソースフォルダーのトップにモジュール定義ファイル(module-info.java)を配置するだけです。

module-info.java

  1. module mynavi {
  2. }

これでmynaviモジュールを定義したことになります(Eclipseでプロジェクトを作成した場合には、[module-info.javaファイルの作成]にチェックを入れると作成されます)。初期の状態では、{…}の中身は空ですが、最低限モジュールを定義するだけであればこれで十分です。この後、「依存するモジュール」「外部に公開するパッケージ」などを設定する際には、{…}配下にコードを記述していくことになります。

他のモジュールを利用する – requires宣言

モジュールの世界では、デフォルトでは異なるモジュールにはアクセスできません。別のモジュールを利用したい場合には、モジュール定義ファイルにrequires宣言を追加してください。たとえば以下は、java.net.httpモジュールを利用する例です(java.net.httpモジュールには、HttpClientなどHTTP通信に関わるクラスが定義されています)。

module-info.java

  1. module mynavi {
  2.   requires java.net.http;
  3. }

requires宣言なしにjava.net.httpモジュールにアクセスした場合、「The type java.net.http.HttpClient is not accessible」のようなエラーとなります。

 

基本的なコードでrequires宣言を意識しなくてもよかったのは、標準ライブラリのjava.lang、java.ioなど主だったパッケージがjava.baseというモジュールに登録されているからです。java.baseモジュールはrequires宣言なしで無条件にアクセスできるというルールがあります。

推移的な依存関係を宣言する – requires transitive宣言

ただし、モジュールが利用しているモジュールをすべて列挙するのは、中々に厄介です。たとえば、モジュールが利用している先のモジュールで利用しているモジュール(=推移的な依存)をすべて把握するのは大概難しいはずです。

しかし、requires transitive宣言では、そうした推移的な依存を表現できます。たとえば、以下のような例です。

  1. module mod1 {
  2.   requires mod2;
  3. }
  4. -----------------------------------------------------------------------------
  5. module mod2 {
  6.   requires transitive java.net.http;
  7.   requires transitive java.sql;
  8. }

この場合、mod1モジュールはmod2モジュール経由でjava.net.http/java.sqlモジュールに依存していますが、mod1側でこれらのモジュールをrequires宣言する必要はありません。これが推移的な依存関係を宣言する、という意味です(よって、太字を削除した場合、mod1モジュールはjava.net.http/java.sqlモジュールを明示的にrequires宣言しなければなりません)。

配下のパッケージを公開する – exports宣言

モジュール配下のパッケージは、デフォルトでモジュールプライベート(=モジュールの外からはアクセスできない)と見なされます。モジュールの外からパッケージへのアクセスを許可するには、exportsで公開したいパッケージを宣言してください。

たとえば以下はmynaviモジュールからcom.example.mynavi.basicパッケージを公開する例です。

  1. module mynavi {
  2.   exports com.example.mynavi.basic;
  3. }

特定のモジュールに対してのみパッケージを公開したいならば、exports…to宣言を利用します。たとえば、以下はhoge/piyoモジュールに対してのみcom.example.mynavi.basicパッケージを公開する例です。

  1. module mynavi {
  2.   exports com.example.mynavi.basic to hoge, piyo;
  3. }

自動モジュール

モジュールはJava 9で導入されたしくみです。よって、アプリによっては非モジュールなコードとモジュール前提のコードとが混在しているかもしれません。このような状態でも、非モジュールをモジュールとして扱えるようにするためのしくみが、自動モジュールです。
具体的には、モジュールパスに配置された.jarファイルで、モジュール定義ファイルを持たないコードは、自動モジュールと見なされます。

 

モジュールパスとは、モジュールの検索先を表すパスのことです。Eclipseであれば、プロジェクトのプロパティから[Javaのビルド・パス]-[ライブラリー]タブから確認できます。

 

▲プロジェクトのモジュールパス

自動モジュールの名前は、以下のルールで決定します。

  • .jarファイルの名前から拡張子とバージョン番号を除去した上で、非英数字をハイフンで置き換えたもの(hoge-piyo-1.0.1.jarならばhoge.piyoがモジュール名)
  • META-INF/MANIFEST.MFのAutomatic-Module-Name属性で宣言された名前(Automatic-Module-Name: hoge.piyo)

自動モジュールはあくまで便宜的なモジュールなので、

  • 配下のすべてのパッケージを公開(exports)
  • モジュールパスに登録されたすべてのモジュールをrequires

したのと同じように動作します。

オブジェクト指向構文_目次
class命令
new演算子
フィールドを定義する
static final修飾子
メソッドを定義する
コンストラクターを定義する
レコード
package宣言
import命令
import static命令
ネストしたクラスを定義する
モジュール

監修

山田祥寛(有限会社 WINGSプロジェクト)
静岡県榛原町生まれ。一橋大学経済学部卒業後、NEC にてシステム企画業務に携わるが、2003年 4 月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト(https://wings.msn.to/)」の代表でもある。主な著書に『改訂 3 版JavaScript 本格入門』(技術評論社)、「独習シリーズ(C#・Python・PHP・Ruby・JSP&サーブレットなど)」(翔泳社)、「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravel など)」(Amazon Kindle)など。売り上げの累計は100万部を超える。