【Java学習|豆知識】Javaの進化と安全性を支える「ケースの優位性ルール」をマスターしよう

導入

近年のJavaアップデートにより、switch式やパターンマッチングが導入され、コードはより簡潔で直感的になりました。しかし、新しい構文を使う上で避けて通れないのが「ケースの優位性ルール(Dominance of cases)」です。このルールを理解していないと、コンパイルエラーに悩まされることになります。本記事では、このルールがなぜ重要で、どのような課題を解決するのかを解説します。

基礎知識

「ケースの優位性ルール」とは、簡単に言えば「より広範な型や条件にマッチするケースを、より狭いケースよりも先に記述してはいけない」というルールです。もし広範なケースを先に書いてしまうと、その後に続く狭いケースが「到達不能(Unreachable)」となり、実行される機会が永久に訪れません。Javaのコンパイラは、コードの安全性を守るために、この到達不能なコードをコンパイルエラーとして検知します。

実装/解決策

解決策は非常にシンプルです。「具体的なものから順に記述する」ことです。例えば、サブクラスを扱う場合、親クラスを先に記述すると、サブクラスのケースが「隠蔽(Dominance)」されてしまいます。そのため、まず特定のサブクラスをチェックし、その後に親クラスやデフォルト(default)ケースを記述するように設計します。

サンプルプログラム

以下のコードは、sealedクラスを使用して、優位性ルールに違反する例と、正しい順序に修正した例を示しています。

// コンパイルエラーを避けるための構造例
public class DominanceExample {
// 継承を制限するsealedクラスの定義
sealed interface Shape permits Circle, Square {}
record Circle(double radius) implements Shape {}
record Square(double side) implements Shape {}

public static void main(String[] args) {
Shape shape = new Circle(5.0);

// 正しい順序:より具体的なサブクラスを先に記述する
String result = switch (shape) {
case Circle c -> “円の面積: ” + (Math.PI c.radius() c.radius());
case Square s -> “正方形の面積: ” + (s.side() s.side());
// すべてのShapeを網羅しているため、defaultは不要(sealedクラスの恩恵)
};
System.out.println(result);

/

  • [NGな例:到達不能エラー]
  • switch (shape) {
  • case Shape s -> “すべて”; // これが先にくると
  • case Circle c -> “円”; // このケースには絶対に到達できないためコンパイルエラー
  • }

/
}
}

応用・注意点

現場で注意すべきは、sealed classes(封印されたクラス)と組み合わせた場合です。すべてのサブクラスを網羅している場合、コンパイラは「網羅性」をチェックしてくれます。もし後からサブクラスを追加した場合、switch式で処理が漏れているとコンパイルエラーで即座に気づくことができます。

また、パターンマッチングを使用する際、nullチェックを内包するパターンを先頭に書くと、その後のcaseでnullを考慮しなくて済むというテクニックもあります。コードを記述する際は、常に「この条件は前の条件に含まれていないか?」を意識することで、堅牢で読みやすいコードを維持できるでしょう。

コメント

タイトルとURLをコピーしました