1. 導入:なぜ「型テストパターン」が重要なのか
Javaで開発をしていると、オブジェクトの型を判定して処理を分ける場面によく遭遇します。これまでのJavaでは、instanceofとキャストを繰り返すコードが一般的でしたが、記述が冗長になり、バグの温床になりがちでした。
最新のJava(Java 17以降のプレビューから正式導入)で利用できる「型テストパターン(Pattern Matching for instanceof)」と「switch式」を組み合わせることで、この課題を劇的に解決し、読みやすく堅牢なコードが書けるようになります。
2. 基礎知識:型テストパターンとは?
型テストパターンとは、instanceof演算子の後ろで「型チェックと同時に変数宣言を行う」仕組みです。
例えば、従来は「if (obj instanceof String) { String s = (String) obj; … }」のように、型チェック後に明示的なキャストが必要でした。型テストパターンを使えば、「if (obj instanceof String s)」と書くだけで、sという変数が使えるようになります。
さらに、これに「Sealed Classes(封印されたクラス)」を組み合わせることで、switch式で「すべての型を網羅しているか」をコンパイラがチェックしてくれるようになり、安全性が飛躍的に高まります。
3. 実装/解決策:モダンな制御フローの書き方
モダンなJavaでは、if-elseの連鎖を避け、switch式を活用します。
Sealed Classesを使用して「継承先を限定」することで、switch文で漏れのない処理(網羅的チェック)が可能になります。これにより、将来的に新しい型を追加した際に、処理の書き忘れをコンパイルエラーとして即座に検知できます。
4. サンプルプログラム
以下のコードは、図形の種類に応じて面積を計算するプログラムです。コピーして実行してみてください。
// 継承先を限定するSealedクラス
sealed interface Shape permits Circle, Rectangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
public class Main {
public static void main(String[] args) {
Shape shape = new Circle(5.0);
System.out.println("面積は: " + getArea(shape));
}
public static double getArea(Shape shape) {
// switch式とパターンマッチングを活用
// yieldを使うことで、値を直接返却できる
return switch (shape) {
case Circle c -> Math.PI c.radius() c.radius();
case Rectangle r -> r.width() r.height();
// sealedクラスにより、これ以外のパターンがないことが保証される
};
}
}
5. 応用・注意点:現場で役立つポイント
1. 網羅性の保証
switch式でSealedクラスを扱う際、すべてのケースを網羅していないとコンパイルエラーになります。これは「修正漏れ」を防ぐ強力な武器になります。もしデフォルト処理が必要な場合でも、可能な限り具体的な型を列挙する設計を心がけましょう。
2. キャスト不要の安全性
パターンマッチングを使う最大のメリットは、キャストミスによる「ClassCastException」が原理的に発生しなくなることです。
3. 現場での導入
古いJava環境から移行する場合、まずはinstanceofの置き換えから始めましょう。それだけでコードの行数が減り、可読性が向上します。Java 17以降の環境であれば、積極的にswitch式への書き換えを検討することをお勧めします。

コメント