導入
Java 17で正式導入された「switch式」は、従来のswitch文とは異なり、値を返すことができる強力な機能です。特に重要なのが「網羅性チェック(Exhaustiveness)」です。これは、すべての条件が考慮されているかをコンパイラが自動でチェックする仕組みです。この機能を活用することで、将来的な機能拡張によるバグ(新しい条件を追加したのに処理が漏れている等)を未然に防ぎ、保守性の高いコードを実現できます。
基礎知識
従来のswitch文は「文」であり、副作用(値の代入やメソッド実行)を目的としていました。一方、switch式は「式」であり、結果を返すことが前提です。
ここで重要なのがSealed Classes(封印されたクラス)との組み合わせです。Sealed Classesは継承できるクラスを制限できるため、switch式と組み合わせることで、「このインターフェースの実装クラスはこれらすべてである」という前提をコンパイラに伝えることができます。これにより、網羅性チェックが完全に機能するようになります。
実装/解決策
網羅性チェックを効かせるためには、以下のルールを守る必要があります。
1. 網羅性を保証する: 全てのパターン(列挙型なら全要素、Sealed Classなら全サブクラス)を網羅する。
2. defaultを安易に使わない: default句を記述すると、コンパイラは「未知のケースも含めてdefaultが処理する」と判断し、網羅性チェックを無効化します。あえて網羅性チェックを強制するために、あえてdefaultを書かない設計が推奨されます。
サンプルプログラム
以下のコードは、Sealed Interfaceを使用した網羅性チェックの例です。仮に新しい型を追加しても、switch式側で処理を追加しなければコンパイルエラーになるため、安全です。
// 封印されたインターフェースの定義
sealed interface Shape permits Circle, Rectangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
public class SwitchExhaustivenessExample {
public static double calculateArea(Shape shape) {
// switch式による網羅性チェック
// もしShapeに新しい実装クラスが増えた場合、ここでコンパイルエラーが発生します
return switch (shape) {
case Circle c -> Math.PI c.radius() c.radius();
case Rectangle r -> r.width() r.height();
// 注意: ここでdefaultを書くと網羅性チェックが機能しなくなります
};
}
public static void main(String[] args) {
Shape shape = new Circle(5.0);
System.out.println(“面積: ” + calculateArea(shape));
}
}
応用・注意点
現場での運用において、特に注意すべき点は「default句の罠」です。
既存のレガシーコードからswitch式へ移行する際、安易にdefault句を記述してしまうと、将来型が追加された際に「コンパイルエラーで気づく」という最大のメリットを捨ててしまうことになります。
また、yieldキーワードについても理解しておきましょう。switch式内で複数の処理が必要な場合は、波括弧 {} を使い、最後に yield で値を返します。
まとめ:
・switch式は網羅性が保証されているかチェックされる。
・Sealed Classesと組み合わせるのがベストプラクティス。
・安易なdefault句の記述は避け、コンパイラの力を借りて安全なコードを維持する。
この仕組みを理解し活用することで、チーム開発における修正漏れのリスクを大幅に低減できます。ぜひ既存のswitch文の置き換えから始めてみてください。

コメント