プロンプトとコンテキスト
チームはJavaのユーティリティやサンプルにおける反復的なインポートを減らしたいと考えており、Java 25のモジュールインポート宣言(Module Import Declarations)の採用を計画しています。単に新しい構文を繰り返すのではなく、セマンティクス、境界、競合処理、移行時のチェックについて説明してください。
面接官が見ているポイント
- モジュールインポートはモジュールによってエクスポートされたパッケージをインポートするものであり、任意の内部要素をインポートするわけではないことを理解しているか。
- モジュール記述子、可読性(readability)、コンパイル時の名前解決について説明できるか。
- 同名型、明示的な単一型インポートの優先順位、APIの可読性を考慮できているか。
- 古いJDK、ビルドツール、コードレビューに対する移行戦略を提案できるか。
尋ねるべき確認の質問
- 実行時の最小JDKは何ですか?また、ビルドチェーンはJava 25の構文をサポートしていますか?
- これは教育用のサンプル、コマンドラインユーティリティ、または長期運用されるモジュール型サービスのどれですか?
- 依存先モジュールは必要なパッケージを安定してエクスポートしていますか?また、複数のパッケージが同じパブリック型名を公開していませんか?
- チームは、すべての依存関係を即座に監査可能にすることよりも、ボイラープレートの削減を重視していますか?
30秒で答える要約
まずコンパイルとランタイムがJava 25以降をターゲットにしているか確認します。import moduleはモジュールのエクスポートされたAPIの一括インポートとして扱い、万能なワイルドカードとは見なしません。これは依存関係が安定し明確な小規模プログラムに適しています。パブリックライブラリやセキュリティ重視のコードでは、明示的なインポートによる可読性のレビューが依然として必要です。移行中はすべてのソースセットをコンパイルし、意図的な同名型のテストを追加し、明示的インポートの優先順位を確認した上で、古いJDKへのフォールバックまたは明示的なアップグレードゲートを維持します。
ステップごとの詳細解説
1. インポートの境界を理解する
JEP 511はJava 25でモジュールインポート宣言を標準化しています。この宣言は、対象モジュールによってエクスポートされたパッケージからアクセス可能な型を現在のコンパイル単位に取り込みます。エクスポートされていない内部パッケージは可視化されません。モジュールシステムのrequiresと可読性(readability)の関係が依然としてアクセスを制御します。
2. パッケージワイルドカードと区別する
モジュールインポートはモジュール境界を使用し、複数のエクスポートされたパッケージをカバーできます。パッケージワイルドカードは1つのパッケージをカバーします。次の構文はJava 25コンパイラでコンパイルする必要があります。
import module java.base;
class Tool {
static void printSize(String value) {
System.out.println(value.length());
}
}モジュールインポートは実装パッケージを公開せず、モジュール記述子の依存関係宣言を置き換えることもありません。
3. 名前の衝突を解決する
異なるエクスポートされたパッケージに同じ型名が含まれている場合があります。解決が曖昧な場合は、単一型インポートまたは完全修飾名を使用してください。コンパイラの偶発的な選択に依存してはいけません。レビュアーが重要なAPIの出所を確認できるよう、明示的なインポートをチームの規約にしてください。モジュールインポートと、java.langなどの暗黙的に可視な型との衝突をテストします。
4. 移行と互換性を計画する
まず分離されたソースセットでJava 25コンパイルを有効にし、その後完全なテスト、静的解析、パッケージングジョブを実行します。IDE、フォーマッタ、アナライザ、インクリメンタルコンパイラがその構文を理解できることを検証します。ライブラリプロジェクトでは利用者の最小JDKを評価する必要があります。古いバージョンを引き続きサポートする場合は、明示的なインポートを維持するか、Java 25専用モジュールに新しい構文を分離して、実行時のアップグレードリスクがすべてのサービスに波及しないようにします。
模範解答
最小JDK、コンパイラ、およびビルドツールがJava 25をサポートしていることを確認します。import moduleは、モジュール境界でエクスポートされたパッケージからアクセス可能な型をインポートします。エクスポートされていない内部要素にはアクセスできず、requiresを置き換えるものではありません。小規模なツール、サンプル、または安定したエクスポート面を持つモジュールに適しています。パブリックライブラリや厳格な監査が必要なコードでは、ボイラープレートの削減と依存関係の可視性を比較検討する必要があります。同名型、java.langとの衝突、および明示的インポートの優先順位に関するテストをコンパイルし、IDE、アナライザ、パッケージングチェーンをチェックします。古いJDKを使用している利用者は、アップグレードゲートと互換性マトリックスが検証されるまで、明示的なインポートを維持します。
よくある間違い
- モジュールインポートがモジュール内のすべてのパッケージを公開すると想定すること。
requiresが自動的に追加される、またはモジュールの可読性(readability)が変更されると想定すること。- 異なるエクスポートパッケージ内の同名型を無視し、曖昧さや誤ったAPIの参照を引き起こすこと。
- CI、IDE、フォーマッタ、またはパッケージングツールを確認せずに、ローカルのJDKのみをアップグレードすること。
- パブリックライブラリで無分別に一括インポートを使用し、依存関係の監査可能性と互換性を低下させること。
- まだ古いJDKを実行している利用者に向けてJava 25の構文を公開すること。
フォローアップ質問と回答
モジュールインポートとパッケージワイルドカードはどのように使い分けますか?
依存関係を安定したモジュール境界で表現すべき場合はモジュールインポートを使用します。パッケージワイルドカードは対象がより狭く、ローカルでの監査が容易です。パブリックAPIや同名型が多いパッケージには、明示的な単一型インポートを優先してください。
インポートされた2つの型が同じ名前を持つ場合はどうなりますか?
複数の候補が一致する場合、コンパイルは曖昧になります。単一型インポートまたは完全修飾名を使用し、インポート順序に依存するのではなく、コードレビューのガイドラインに規約を記録してください。
Java 21とJava 25をどのようにサポートしますか?
明確なコンパイルマトリックスを作成します。共有ソースは明示的なインポートを維持し、Java 25固有のソースセットのみがモジュールインポートを使用します。リリース前に、バイトコード、テスト、および各利用者が受け入れ可能な最小バージョンを検証します。