はじめに
JDK 25 からインポート宣言にモジュール名を指定できるようになります。
import module java.base;
例えば以下のようなストリーム処理を行う単純なコードは、
String[] fruits = new String[] { "apple", "berry", "citrus" }; Map<String, String> m = Stream.of(fruits) .collect(Collectors.toMap( s -> s.toUpperCase().substring(0,1), Function.identity()));
以下の単一型インポート宣言(single-type-import)が必要で、ストリーム処理のコードと同じ行数が必要となります。
import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream;
オンデマンド型インポート宣言(type-import-on-demand)(いわゆるスターインポート)を使ったとしても、3行のインポート宣言が必要です。
import java.util.*; import java.util.function.*; import java.util.stream.*;
モジュールインポートを使えば、以下の宣言で完了します。
import module java.base;
モジュールインポートは、JDK 23でプレビュー公開(JEP 476)され、JDK 24で改良されたセカンドプレビュー公開(JEP 494)となったものがJDK 25でそのまま最終版として提案されました。
モジュールインポート
インポート宣言の文法に ModuleImportDeclaration
が追加となります。
ImportDeclaration: SingleTypeImportDeclaration TypeImportOnDemandDeclaration SingleStaticImportDeclaration StaticImportOnDemandDeclaration ModuleImportDeclaration ModuleImportDeclaration: import module ModuleName;
以下のようなインポート宣言は、
import javax.xml.*; import javax.xml.parsers.*; import javax.xml.stream.*;
以下のように簡略化して書くことができます。
import module java.xml;
モジュールインポートの特徴は以下になります。
- モジュール全体を一度に(オンデマンド)インポートできる
- インポート宣言を行うコード自体は、モジュール定義されたものでなくとも良い
- モジュール宣言で
exports
されたパッケージに加え、requires transitive
で遷移的に依存するモジュールも合わせてインポート処理される - 名前のないモジュールをモジュールインポートすることはできない
- モジュールインポートは、他のインポート宣言より優先度が低い(他のインポート宣言でシャドーイングできる)
特に説明が必要なのは、モジュールインポートの優先度(特定性)ぐらいでしょう。
以下のようにモジュールインポートを行った場合、Date
クラスの使用はエラーになります。
import module java.base; import module java.sql; Date d = ... // Error - java.util,Date vs java.sql,Date
java.util,Date
か java.sql,Date
かを特定できないためです。
このような曖昧さを解消するには、単一型インポート宣言を追加してモジュールインポートをシャドーイングします。
import module java.base; import module java.sql; import java.sql.Date; Date d = ... // Ok! Date は java.sql.Date として解決される
つまり、インポート宣言の特定性は以下の順に高くなり、上のものは下のものでシャドーイングできます。
- モジュールインポート
- オンデマンド型インポート(type-import-on-demand)
- 単一型インポート(single-type-import)
まとめ
JDK 25 からモジュール名を指定した一括インポートが可能になりました。
大規模なプロジェクトでは、単一型インポート(single-type-import)を使用しておくのがベータです(例えば OpenRewrite などで大規模なマイグレーションを行う際に後悔することになる)。
が、教育目的やプロトタイプ開発、小規模開発時には便利に使えるでしょう。
JEP 512: Compact Source Files and Instance Main Methodsでは暗黙的に import module java.base;
されたものとして扱われます。また、これは JShell についても同様です。