switch は何のためにあるか
switch は 1 つの値を固定された選択肢のリストと比較し、一致した分岐を実行します。同じ変数をさまざまな定数と何度もテストする長い if/else if のチェーンを書いていることに気づいたら、switch は同じことをより明快に表現します。
これはコンパイル時定数との等価チェックしか行いません。範囲をテストしたり条件を組み合わせたりはできません。それらには if/else のままにしましょう。
古典的な switch 文
伝統的な形式は、コロン付きの case ラベルと、各分岐のあとの break を使います。
Java は day を評価し、一致した case へジャンプして、その文を実行し、break で switch を抜けます。default 分岐は他に何も一致しなかったときに実行されます。else のようなものと考えてください。これは省略可能ですが、予期しない値が静かにすり抜けないように、含めておくのが良い習慣です。
break の罠:フォールスルー
これは switch で最もよくあるバグです。break を省くと、実行は一致した case の終わりで止まりません。次の case へとフォールスルーし、break か閉じ括弧に到達するまで実行を続けます。
Level 1 だけを期待するかもしれませんが、これは 3 行すべてを出力します。case 1 に break がないため、制御はそのまま case 2 と case 3 へ滑り込みます。本当にフォールスルーが必要なのでない限り、必ず break を付けましょう。そしてフォールスルーに頼るときは、次に読む人が意図的だとわかるようにコメントを残しましょう。
case のグループ化
フォールスルーには 1 つの正当できれいな用途があります。複数の値が 1 つのブロックを共有するように case ラベルを積み重ねることです。ラベルの間にコードを置かず、続けて並べます。
ここでは 'A'、'B'、'C' がすべて同じ "Pass" の行を実行します。これが「これらの値のいずれも同じことをする」と表現する意図された方法です。
文字列に対する switch
数値に限られているわけではありません。Java 7 以降、String で switch でき、メニューの選択肢やコマンド名に最適です。
マッチングは大文字・小文字を区別します。"Stop" は "stop" に一致しないので、入力の大文字・小文字が変わりうるなら、まず正規化してください(たとえば command.toLowerCase())。もう 1 つの落とし穴:command が null の場合、switch は NullPointerException をスローするので、そこに到達する前に null を防いでください。
モダンなアロー構文
新しい Java(14 以降)は、フォールスルーの罠を設計で解消するアロー形式 case label -> ... を追加しました。各アロー case はちょうど 1 つの分岐を実行し、決してフォールスルーしないので、忘れるべき break はありません。
ラベルを積み重ねる代わりにカンマで値をグループ化していること(case 6, 7)に注目してください。break は 1 つも見当たりません。複数の文にはブロックを使います:case 1 -> { ...; ... }。新しいコードではこの形式を優先しましょう。短く、バグのまるごと 1 クラスを取り除けます。
式としての switch
アロー形式は値を生成することもできます。switch 式は、そのまま変数に代入できる結果を返します。一時変数も、各分岐での繰り返しの代入も不要です。
switch (...) { ... } 全体が、days に格納される数値に評価されます。閉じ括弧のあとのセミコロンに注意してください。これは代入文の一部です。switch 式は網羅的でなければなりません(あらゆる可能な値をカバーする必要があります)。だからここに default があるのです。分岐が値を返す前に複数の文を必要とする場合は、yield を使ったブロックを使います。
case 2 -> {
boolean leap = (year % 4 == 0);
yield leap ? 29 : 28;
}
yield は、アローブロックがその値を返す方法であり、結果を運ぶ break の、式の世界における相当物です。
次:for ループ
switch は多くの分岐から 1 つを選びます。ときには、その代わりにブロックを何度も繰り返す必要があります。for ループは、制御された回数だけコードを実行し(範囲を数えたり、各要素をたどったり)、それが次のページです。
よくある質問
Java で if-else ではなく switch を使うべきなのはどんなときですか?
1 つの値を、固定された定数の多数の選択肢と比較するとき、たとえば曜日の番号、メニューの選択肢、enum などと比較するときに switch を使いましょう。長い if/else if のチェーンよりも明快に読め、「これらの既知の値の中から 1 つの分岐を選ぶ」という意図を伝えます。条件が範囲(x > 10)、複数の変数、あるいは定数との単純な等価チェックでない何かを含むときは if/else のままにしましょう。
Java の switch 文ではなぜ break が必要なのですか?
古典的なコロン構文では、ある case が一致すると、break か switch の終わりに到達するまで、実行は後続の case へとフォールスルーします。break はそれを止めます。これを忘れるのは典型的なバグです。case 1: に一致したのに、誤って case 2:、case 3: などのコードまで実行してしまうのです。新しいアロー構文(case 1 -> ...)は決してフォールスルーしないので、break はまったく書きません。
Java の switch 文は文字列(String)で動作しますか?
はい。Java 7 以降、String で switch でき、さらに int、char、byte、short、それらのラッパー型、そして enum の値でも switch できます。long、double、float、boolean では switch できません。文字列のマッチングは大文字・小文字を区別するので、"Yes" と "yes" は別の case です。