代表的な面接トピック

Javaコーディング面接:プリミティブ型パターンはinstanceofとswitchをどう変えるか?

コーディング難しい
Offer.cc 編集チーム公開日 更新日

質問

Java 25のサービスで、パターンマッチングを用いて数値を分類しようとしています。プリミティブ型パターンがinstanceofやswitchにどのような影響を与えるか、縮小変換が拒否されるケース、nullの処理方法、そしてこのプレビュー機能を採用または回避する方法について説明してください。

課題とスコープ

あなたのチームは、instanceofswitch、およびレコードパターンにおけるJava 25のプリミティブ型パターンのプレビュー機能を評価しています。コードはパーサーからNumber値を受け取り、予期せぬ縮小変換やnullによる障害を起こさずに、整数および浮動小数点のケースを分類しなければなりません。言語規則を説明し、短いコード例を記述し、互換性と展開に関する判断を示してください。

JEP 507はJava 25のプレビュー機能です。適切な回答では、プレビュー構文には明示的なコンパイラおよびランタイムフラグが必要であり、自動的に安定した本番用コントラクトになるわけではない点に言及する必要があります。

面接官がテストしているポイント

  • 参照パターン、プリミティブパターン、およびボクシング変換の違いを理解しているか。
  • 安全な拡大変換(widening)、危険な縮小変換(narrowing)、および情報の損失について説明できるか。
  • nullNaN、無限大、およびセレクター型を明示的に処理しているか。
  • switchの完全性(網羅性)の挙動とプレビュー機能の互換性の境界を理解しているか。
  • 記述が短く見えるという理由だけで構文を採用するのではなく、テストやフォールバックを設計できるか。

面接官が求めているのは、JEP番号の羅列ではなく、規則と反例です。

最初に確認すべき明確化の質問

  1. CIおよび本番環境のビルドでプレビュー機能の使用が許可されていますか? 許可されていない場合、ソリューションはJava 21時代のパターンまたは明示的な変換を使用する必要があります。
  2. 「数値を分類する」とは元の値をそのまま保持することですか、それとも制限された整数結果でも許容されますか? それによって縮小変換が正当かどうかが変わります。
  3. nullは拒否すべきか、UNKNOWNにマッピングすべきか、専用のswitchアームで処理すべきですか?
  4. NaNや無限大は有効な入力ですか? 数値型のマッチングによって、これらが通常の有限値に変換されるわけではありません。
  5. 同じソースコードを非プレビュー版のJDKでコンパイルする必要がありますか? その場合、プレビューコードをモジュールの背後に分離するか、安定した実装を維持してください。

30秒の回答フレームワーク

「Java 25のJEP 507プレビューにより、以前はボクシングや扱いにくいガードが必要だったコンテキストで、パターンにプリミティブ型を指定できるようになりました。コンパイラはパターン規則の下で安全な変換を許可し、情報が失われる可能性のある縮小変換を拒否します。私ならプリミティブマッチングの前にnullを処理し、Integer.MAX_VALUENaN、無限大などの境界値をテストし、ツールチェーンでプレビューフラグを維持します。デプロイ環境でプレビューを有効にしたJava 25を固定できない場合は、代わりに安定したswitchまたは明示的に検証された変換を使用します。」

ステップバイステップの解決策

1. 値の静的型から始める

パターンの互換性は、あらゆる数値を任意のプリミティブに変換できる許可証ではありません。Numberの参照には、IntegerLongDouble、またはその他の実装が含まれる可能性があります。最初に参照ラッパーを認識してアンボクシングを行うパターンは、プリミティブセレクターに対するプリミティブ型パターンとは異なるコントラクトを保持します。網羅性について議論する前に、セレクターの型と変換の方向を明記してください。

java
static String classify(Number value) {
    if (value == null) {
        return "missing";
    }
    return switch (value) {
        case Integer i -> "int:" + i;
        case Long l -> "long:" + l;
        case Double d when Double.isNaN(d) -> "nan";
        case Double d -> "double:" + d;
        default -> "other";
    };
}

この安定した例はラッパー型とマッチングします。すべてのNumberが安全にintへと縮小変換できると主張しているわけではありません。

2. 拡大変換と縮小変換の違いを説明する

JEP 507はプリミティブパターンを体系化し、変換がパターン変数にとって安全な場合に、パターンがプリミティブ値とマッチできるようにします。intからlongへの拡大変換はすべての値を保持します。longからintへの縮小変換は上位ビットを破棄する可能性があるため、そのような変換を暗黙的に受け入れるパターンは危険です。回答では、拒否される変換を挙げ、縮小変換がビジネス要件である場合は明示的な範囲チェックを提案する必要があります。

java
static String bucket(long value) {
    if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
        int narrowed = (int) value;
        return "small:" + narrowed;
    }
    return "wide:" + value;
}

これでキャストは目に見える不変条件によって保護されます。パターンはその証明の代わりにはなりません。

3. nullの処理をプリミティブマッチングから分離する

プリミティブ値をnullにすることはできませんが、ボクシングされたセレクターは可能です。参照セレクターに対するswitchは、暗黙的にnullを数値ケースとして扱うことはありません。ドメインが完全な結果を必要とする場合はcase nullを追加するか、switchの前に拒否してください。予期しないnullや未知のラッパーを隠すためにdefaultアームを使用しないでください。それらのケースには異なる運用の対応が必要です。

浮動小数点値の場合、double型にマッチしたからといって、値が有限であるとは限りません。後続のコードが順序付けや算術演算を前提としている場合は、NaN、正の無限大、負の無限大に対する明示的なチェックを維持してください。

4. 意図的に網羅的なswitchを構築する

プリミティブパターンと定数によってswitchを簡潔に記述できますが、網羅性は依然としてセレクターのドメインとガードに依存します。ガード付きケースはその型のすべての値をカバーするわけではありません。残りの部分にはガードなしのケースまたはdefaultを使用し、null許容のセレクターにはcase nullを含めてください。switchが請求、パース、またはセキュリティポリシーに使用される値を返す場合は、暗黙的に受け入れるのではなく、フォールバックを監視可能にしてください。

5. プレビューの境界を確認する

JEP 507はJava 25のプレビュー機能です。コンパイルと実行には対応する--enable-previewオプションが必要であり、source/targetリリースは選択したJDKと一致している必要があります。プレビュー構文は以降のリリースで変更または削除される可能性があります。CIは安定したフォールバックもコンパイルすべきであり、成果物にはJDK、プレビューフラグ、および言語レベルを記録する必要があります。ライブラリは、公開APIを呼び出すためだけに利用側へプレビューの有効化を強制することを避けるべきです。

6. 代替手段を比較する

入力が異種混在のNumberであり互換性が重要な場合は、明示的なラッパーパターンを使用します。セレクターがすでにプリミティブであり、デプロイ環境でプレビューツールチェーンを固定できる場合は、プリミティブswitchを使用します。ビジネスルールが「32ビットに収めること」である場合は、検証済み変換を使用します。範囲チェックは意図を明確にし、構文の変更にも耐えられるためです。ソースコードが短いことは、より安全な数値コントラクトであることの証拠にはなりません。

高品質な模範回答

「私ならまずセレクターとnullポリシーを明記します。Java 25 JEP 507はプレビュー機能であるため、安定した構文としては提示しません。プリミティブパターンにより、instanceofswitch、およびレコードパターン全体でより安全で統一的なマッチングが可能になりますが、縮小変換を無損失にするわけではありません。intからlongへの拡大変換は値を保持しますが、longからintへの変換には明示的な範囲の証明が必要です。ボクシングされた入力に対しては、nullを処理し、ラッパー型を区別し、NaNと無限大を個別に分類します。すべてのswitchには意図的な残余処理を持たせ、ガード付きケースが完全な網羅性を提供するわけではない点に留意します。本番環境でプレビューを有効にしたJava 25を固定できない場合は、ラッパーパターンや明示的なチェックを維持し、CIで両方のパスをコンパイルします。テストには、null、すべての数値境界、重複表現、NaN、無限大、および非プレビュービルドを含めます。」

よくある間違い

  • プレビュー構文を安定しているとみなす → 将来のJDKで変更または削除される可能性がある → JDKを固定し、フォールバックを維持する。
  • すべての数値変換が安全であると想定する → 縮小変換によりビットが失われたり値が拒否されたりする → 変換を明示し、その範囲を証明する。
  • defaultにnullを吸収させる → nullと未知の型には異なる処理が必要 → case nullを追加するか、マッチングの前に拒否する。
  • doubleへのマッチを有限値として扱う → NaNや無限大もプリミティブ型を満たす → これらを明示的にテストして分類する。
  • ガード付きケースを網羅的として扱う → ガードを満たさない値はマッチしないまま残る → ガードなしの残余ケースを追加し、テストカバレッジを確保する。

フォローアップ質問と回答

longパターンはintセレクターを安全にバインドできますか?

はい、拡大変換によってintの値は保持されます。逆方向は、longintの範囲を超える可能性があるため、一般的には安全ではありません。ドメインで境界が保証されている場合は、チェックを明示的に記述し、両方の境界値をテストしてください。

すべての値を単にボクシングしないのはなぜですか?

ボクシングによって異種混在の入力の検査が容易になる場合がありますが、アロケーションとラッパーのセマンティクスが追加され、変換で値が保持されることの証明にはなりません。数値に関する論理的推論を避ける手段としてではなく、APIの互換性のために選択してください。

プレビュー実装をどのようにテストしますか?

プレビュー実装と安定したフォールバックの両方に対して同じケースを実行します:null、ゼロ、最小値および最大値、1つ範囲外の値、NaN、両方の無限大、未知のラッパー、ガード付きケースの不一致、および不正な形式の入力。CIで正確なreleaseフラグとpreviewフラグを使用してコンパイルし、その後、非プレビューの互換性ジョブを実行します。

Java 26でプレビュー規則が変更されたらどうしますか?

言語レベルを成果物のコントラクトの一部として扱います。新しいリリースノートを確認し、候補ブランチをコンパイルし、フォールバックテストとセマンティクスを比較した上で、ソースコードとランタイムのマトリックスに合格した後にのみプロモートします。本番環境で新しいプレビューフラグを暗黙的に有効にしてはなりません。

公開情報ソース

関連する質問

関連面接ツール

コーディング問題にはスクリーンショットを使用

問題をキャプチャし、制約条件、解法アプローチ、コード、エッジケース、計算量の順に進めます。

ツールを見る