【Java学習|実務向け】Java 17以降の必須スキル:Switch式で例外をスマートに投げるテクニック

導入

Java 14で導入され、Java 17で正式採用されたSwitch式は、従来のSwitch文よりも堅牢で簡潔な記述を可能にしました。特に「網羅性のチェック」がコンパイラによって行われる点は、バグの温床を減らす大きな武器です。しかし、実務では「想定外の値が来た場合に例外を投げたい」というケースが頻繁に発生します。本稿では、Switch式で例外をスマートに投げる手法と、その背後にある制御フローの考え方を解説します。

基礎知識

従来のSwitch文は「文(Statement)」であり、値の代入には一時変数が必要でした。対してSwitch式は「式(Expression)」であり、値を直接返すことができます。
Switch式では、全ての入力に対して結果を定義する必要があります。もし網羅性が足りなければコンパイルエラーになります。ここで「例外を投げる」ことは、実行時における「想定外のケース」を明示的に遮断する重要な役割を果たします。

実装/解決策

Switch式で例外を投げるには、通常の `throw` 文をそのまま記述します。Switch式の矢印演算子(`->`)の右側は「ブロック」または「式」を取れます。`throw` は式ではないため、単一の値として扱う場合はブロック `{ … }` 内に書く必要があります。

サンプルプログラム

以下のコードは、列挙型(enum)に基づいた処理をSwitch式で行い、想定外の入力に対して `IllegalArgumentException` を投げる実用的な例です。

public class SwitchExceptionExample {

public enum Status { NEW, ACTIVE, CLOSED }

public String processStatus(Status status) {
// Switch式で網羅性を担保しつつ、例外をスローする
return switch (status) {
case NEW -> “初期化中”;
case ACTIVE -> “稼働中”;
case CLOSED -> “終了”;
// nullが渡された場合や、将来的にenumが増えた際のガードとして例外を投げる
// throwは式ではないため、ブロックで囲む必要がある
default -> {
throw new IllegalArgumentException(“未対応のステータスです: ” + status);
}
};
}

public static void main(String[] args) {
var example = new SwitchExceptionExample();
System.out.println(example.processStatus(Status.NEW));
}
}

応用・注意点

現場でこの手法を用いる際、特に意識すべき点は以下の3つです。

1. Sealed Classとの組み合わせ
Sealed Class(封印クラス)とSwitch式を組み合わせることで、`default` ブロックを排除しつつ、網羅性をコンパイラに保証させることができます。これにより、例外を投げる必要すらなくなるケースが多いです。設計段階でSealed Classを検討してください。

2. nullチェックの重要性
Switch式で `null` を扱う場合、`case null -> throw …` と明示的に書くか、Switch式に入る前にバリデーションを行うのがJavaのベストプラクティスです。`null` を放置すると `NullPointerException` が発生し、スタックトレースが追いづらくなることがあります。

3. 網羅性と例外のバランス
「何でもかんでもdefaultで例外を投げる」のは設計の敗北です。可能な限り `enum` や `Sealed Class` の型安全性を利用し、本当に「あり得ないはずのコードパス」に到達した時のみ `throw` するよう心がけてください。そうすることで、例外が発生した際に「ロジックの不整合」が即座に判明するようになります。

コメント

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