Java | Java 詳細・モダン文法:言語仕様詳細 – null 許容と switch

Java Java
スポンサーリンク

なぜ「null と switch」をちゃんと考えないといけないのか

switch は「値に応じて分岐する」構文ですが、
その値が null になりうるかどうかを意識していないと、
実行時にいきなり NullPointerException(NPE)が飛ぶポイントになります。

昔の switch は「null を絶対に許さない」仕様でしたが、
モダンな switch(switch 式・パターンマッチング付き switch)では、
null明示的に扱う ことができるようになってきています。

ここでは、

  • 旧来の switchnull の関係
  • モダンな switch での null の扱い
  • 設計として「null をどう位置づけるか」

を、初心者向けにかみ砕いて整理していきます。


旧来の switch:null を渡した瞬間に NPE

古い switch 文の挙動

まず、昔ながらの switch 文から。

String s = null;

switch (s) {
    case "A":
        System.out.println("A");
        break;
    default:
        System.out.println("other");
}
Java

これを実行すると、default に行くのではなく、
switch (s) の時点で NullPointerException が発生します。

理由はシンプルで、
旧来の switch は「null を値として扱う」ことを想定していないからです。

つまり、

  • switch に渡す値が null になりうるなら、
    事前に if (s == null) でチェックしておかないと危険

というのが、昔からの鉄則でした。


switch 式(Java 14+)でも基本は同じ:null はそのままでは NPE

switch 式も「素のままでは null 非対応」

モダンな switch 式でも、基本は同じです。

String s = null;

String label = switch (s) {
    case "A" -> "エース";
    case "B" -> "ビー";
    default  -> "その他";
};
Java

これも、default に行く前に NullPointerException になります。

switch 式になっても、
null を勝手に default に流してくれる」ような甘い仕様にはなっていません。

だからこそ「null をどう扱うか」を設計で決める必要がある

ここで大事なのは、

  • 「この switch に渡す値は、そもそも null を許すのか?」
  • 「許すなら、null のときはどういう扱いにするのか?」

を、コードの外側(設計)でちゃんと決めることです。

「とりあえず switch に投げて、default でなんとかする」
という発想だと、null が来た瞬間に落ちます。


パターンマッチング付き switch と null

パターンマッチング付き switch のイメージ

パターンマッチング付き switch(Java 21 以降の機能)では、
switch の中で「型」や「条件」に応じて分岐できます。

static String describe(Object obj) {
    return switch (obj) {
        case String s -> "String: " + s;
        case Integer i -> "Integer: " + i;
        default -> "other";
    };
}
Java

ここでも、objnull なら、
やはり switch (obj) の時点で NullPointerException です。

「null というパターン」を明示的に書けるようになっていく

将来の仕様・プレビュー機能では、
case null のように「null そのもの」をパターンとして扱う方向に進んでいます。

イメージとしては、こういう書き方です。

String result = switch (obj) {
    case null        -> "null でした";
    case String s    -> "String: " + s;
    case Integer i   -> "Integer: " + i;
    default          -> "other";
};
Java

こうなると、

  • null を「特別なケース」として明示的に扱える
  • null を見落として NPE になる、という事故を減らせる

という方向に進化していきます。

ただし、ここでのポイントは、
null を勝手に安全にしてくれる」のではなく、
null をパターンとして“明示的に扱え”と言っている」

ということです。


実務での基本スタンス:「switch に null を渡さない」設計

そもそも null を許さないようにする

一番シンプルで堅い方針は、

switch に渡す値は、そもそも null にならないようにする」

です。

例えば、メソッドの引数であれば、

void handleStatus(Status status) {
    Objects.requireNonNull(status, "status must not be null");

    switch (status) {
        case OK    -> ...
        case ERROR -> ...
    }
}
Java

のように、入り口で null をはじく

あるいは、Optional を使って、
null ではなく Optional.empty() で表現する」
という設計に寄せるのも有効です。

Optional<String> opt = ...;

String label = opt
        .map(s -> switch (s) {
            case "A" -> "エース";
            case "B" -> "ビー";
            default  -> "その他";
        })
        .orElse("値がありません");
Java

switch の中には「非 null の世界」だけを持ち込み、
null の扱いは Optional の外側で完結させる、という発想です。

どうしても null を許すなら、前段で分岐する

「歴史的事情で null が来る可能性がある」
「外部ライブラリの仕様で null が返ってくる」

といった場合は、switch の前で分岐してしまうのが現実的です。

String s = getMaybeNull();

String label;
if (s == null) {
    label = "null のときの扱い";
} else {
    label = switch (s) {
        case "A" -> "エース";
        case "B" -> "ビー";
        default  -> "その他";
    };
}
Java

null を扱う if」と「値に応じて分岐する switch」を分離することで、
switch の中を「非 null 前提の世界」にできます。


設計としての一番大事なポイント:「null を“値”として認めるか?」

null を「普通の値」として扱うと、だいたい破綻する

null を「他の値と同列の、ただの 1 つの値」として扱い始めると、
コードのあちこちで

  • if (x == null)
  • switch の前の null チェック
  • 想定外の NPE

が増殖していきます。

switch もその一部で、
null を普通の値として switch に渡す」
という発想自体が、だいたいコードをつらくします。

「この場では null を許さない」と決めてしまう勇気

だからこそ、設計としては、

  • 「このメソッドの引数は null 禁止」
  • 「このフィールドは必ず値が入る」
  • 「null の可能性があるのは、この層まで」

といった “null の侵入範囲” を決めておくことが大事です。

switch は「値に応じて分岐する」構文なので、
その値が「ちゃんと存在する」前提で使う方が、
読みやすくて安全なコードになります。


まとめ:null と switch を自分の言葉で整理するなら

あなたの言葉でまとめると、こうなります。

「旧来の switch もモダンな switch 式も、
switch (x)null を渡すと NullPointerException になる。
モダンなパターンマッチング付き switch では、
case null のように null を明示的に扱う方向に進化しているが、
それは“勝手に安全になる”のではなく、“null をちゃんとパターンとして扱え”というメッセージ。

実務では、
・そもそも switch に渡す値は null を許さない設計にする
・どうしても null が来るなら、switch の前段で if で分岐する
・必要なら Optional で「値がない」ことを表現し、switch の中は非 null の世界にする

という方針で考えると、
switchnull の組み合わせで悩むことがかなり減る。」

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