1. 導入
実務において、APIレスポンスの処理や複雑なドメインオブジェクトの判定を行う際、型に応じた分岐処理は避けて通れません。しかし、Javaのジェネリクスには「型消去(Type Erasure)」という制約があり、実行時に型情報を直接判定できないという課題があります。本記事では、この制約を理解し、Sealed Classes(封印クラス)と最新のSwitch Expressionsを組み合わせて、安全かつクリーンに分岐を実現する方法を解説します。
2. 基礎知識
Javaのジェネリクスはコンパイル時にのみ型チェックが行われ、実行時にはObject型として扱われます(型消去)。そのため、例えば `if (obj instanceof List
3. 実装/解決策
この課題に対するモダンな解決策は、Sealed Classes(封印クラス)とPattern Matching for switchの組み合わせです。Sealed Classesを使用すると、「継承される型」をコンパイル時に限定できるため、実行時の型判定が安全かつ網羅的になります。これにより、型消去の制約を回避しつつ、Switch式で型に応じた柔軟な制御フローを構築できます。
4. サンプルプログラム
以下は、異なるデータ型を扱うレスポンス処理を、Sealed InterfaceとSwitch式で実装した例です。
// 1. Sealed Interfaceで型を定義(継承を限定する)
sealed interface ApiResult
record Success
record Failure(String message, int code) implements ApiResult
public class SwitchGenericExample {
public static void main(String[] args) {
ApiResult
// 2. Switch式によるパターンマッチング(Java 17/21以降)
String output = switch (result) {
// パターンマッチングにより型安全に抽出
case Success
case Failure f -> “Error (” + f.code() + “): ” + f.message();
};
System.out.println(output);
}
}
5. 応用・注意点
現場でこの技術を使う際、以下のポイントに注意してください。
網羅性の保証:
Sealed Classesを使用すると、Switch式において全てのケースをカバーしているかコンパイラがチェックしてくれます。もし `permits` に新しい型を追加した場合、Switch式側で `case` を追加しないとコンパイルエラーになるため、バグを未然に防げます。
型消去の限界:
Switch式でも `List
注意点:
レガシーな環境(Java 16以前)ではこの手法が使えないため、その場合は従来通り `instanceof` を使用したメソッドオーバーロードや、Visitorパターンへの切り替えを検討してください。最新のJava環境であれば、今回紹介したアプローチが最も保守性の高い選択肢となります。

コメント