パソナについて
記事検索

【Java入門】switch-caseとは?基本の文法から便利な使い方まで

今回は、Javaにおけるswitch文の基本的な文法から、より便利な使い方までを紹介していきます。文字列や列挙型との組み合わせ方や、switch-case全体に値をもたせる「switch式」についても説明するので、ぜひ参考にしてください。

【Java入門】switch-caseとは?基本の文法から便利な使い方まで

今回は、Javaにおけるswitch文の基本的な文法から、より便利な使い方までを紹介していきます。文字列や列挙型との組み合わせ方や、switch-case全体に値をもたせる「switch式」についても説明するので、ぜひ参考にしてください。

スキルアップ

2022/12/19 UP

「switch文(switch-case)」は、さまざまなプログラミング言語で使える構文です。しかし、どれも同じというわけではありません。特にJavaのswitch文には独特の記法や用法があるため、詳しく知らないままでいるのは損だといってもよいでしょう。

そこで今回は、Javaにおけるswitch文の基本的な文法から、より便利な使い方までを紹介していきます。文字列や列挙型との組み合わせ方や、switch-case全体に値をもたせる「switch式」についても説明するので、ぜひ参考にしてください。

Javaのswitch文とは

まずは、Javaにおけるswitch文の基本を確認しておきましょう。

switch文の基本形

switch文は、プログラムを分岐させるための構文の一つです。次の例のように2つ以上の分岐先を作っておき、値によってプログラムの流れを枝分かれさせられます。

サンプルコード:

public class Main {
    public static void main(String[] args) {
        var value = 3;
        var result = "";

        switch (value) {
            case 1:
            case 2:
                result = "1または2";
                break;
            case 3:
            case 4:
                result = "3または4";
                break;
            default:
                result = "そのほか";
        }

        System.out.println("結果:" + result);
    }
}

実行結果:

結果:3または4

caseとdefaultが、switch文の分岐先にあたります。与えられた式の評価結果に応じて、一致するcaseに分岐するのが基本の流れです。そこから下に向かって処理が実行され、breakに出会うと残りの処理はスキップされます。

上記のプログラムでは式として「value」が与えられているため、その評価結果「3」によって、「case 3」以降が実行されている様子がわかるでしょう。

なお、defaultは一致するcaseが存在しない場合の分岐先です。不要な場合は省略してもかまいません。

if文との比較

switch文の意味は、if文の連鎖で表現すると理解しやすいでしょう。以下は、上記のswitch文をif文で書き換えて、同じ結果になるようにした例です。

if ((value == 1) || (value == 2)) {
    result = "1または2";
} else if ((value == 3) || (value == 4)) {
    result = "3または4";
} else {
    result = "そのほか";
}

ここでは、breakで終わる部分ごとに、if文が対応している様子が確認できます。連続するcaseは、if文の式にOR条件(論理演算子の「||」)を記述するようなものだということもわかるでしょう。また、default以降の部分は、最後のelseで行なう処理に相当します。

if文による分岐について詳しく知りたい場合は、こちらの記事もチェックしてみてください。
【Java入門】if else で条件分岐させる書き方 - サンプルコードを元に徹底解説

switch文のフォール・スルーとは

switch文の制御は、分岐先のcaseから下に向かっていくのが特徴です。このとき、途中に別のcaseがあっても、処理は問題なく続いていきます。これは、「フォール・スルー」と呼ばれる動作です。

フォール・スルーの動作は、breakに出会うまで止まりません。これは、switch文ではbreakの使い方に注意が必要なことを意味しています。

意図せず発生するフォール・スルー

あらためて上記のサンプルコードを振り返ると、実際にフォール・スルーが発生するswitch文の例だったことがわかるでしょう。実行すると「case 3」に分岐し、そのまま「case 4」を通過して、breakに出会うまでの1行が処理されます。

では、breakを書き忘れたとしたら、switch文の動作はどのように変わるでしょうか。以下は、上記のサンプルコードからbreakを取り除いたものです。

サンプルコード:

public class Main {
    public static void main(String[] args) {
        var value = 3;
        var result = "";

        switch (value) {
            case 1:
            case 2:
                result = "1または2";
            case 3:
            case 4:
                result = "3または4";
            default:
                result = "そのほか";
        }

        System.out.println("結果:" + result);
    }
}

実行結果:

結果:そのほか

実行結果から、制御がdefaultまで到達していることがわかります。このように、breakを書き忘れると意図しないフォール・スルーが発生し、期待と異なる動作になってしまうのです。

switch文では、breakが重要な役割を果たしていることがわかるでしょう。

Javaのswitch文でbreakを使わない記法

Javaのswitch文には、breakを用いない記法も用意されています。上記のswitch文を、breakなしで書き直してみましょう。

switch (value) {
    case 1, 2 -> {
        result = "1または2";
    }
    case 3, 4 -> {
        result = "3または4";
    }
    default -> {
        result = "そのほか";
    }
}

1つのcaseに対して、複数の値を記述しているのがわかるでしょうか。これにより、caseを連続で記述してフォール・スルーさせるのと同等の分岐を表現できます。

また、この記法ではbreakを用いません。そもそもbreakを書き忘れる恐れがないため、意図と異なる結果になるのを避けやすい書き方だといえるでしょう。

なお、この例のようにcaseごとの処理が1行しかない場合は、次のように省略した記述も可能です。

switch (value) {
    case 1, 2 -> result = "1または2";
    case 3, 4 -> result = "3または4";
    default -> result = "そのほか";
}

最初のswitch文と比べると、かなりコンパクトになっているのがわかるでしょう。

Javaのswitch文で文字列を使用する

Javaでは、文字列の値で分岐するswitch文も記述可能です。その具体例と、注意が必要な点について説明します。

文字列の値で分岐するswitch文の記法

switch文に文字列を使う際の文法は、数値を使う場合と変わりません。以下は文字列を使用したswitch文の、breakなしの記法によるサンプルプログラムです。

サンプルコード:

public class Main {
    public static void main(String[] args) {
        var value = "Saturday";
        var result = "";

        switch (value) {
            case "Sunday", "Saturday" -> {
                result = "休日";
            }
            case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" -> {
                result = "平日";
            }
            default -> {
                result = "不明な曜日";
            }
        }

        System.out.println("結果:" + result);
    }
}

実行結果:

結果:休日

文字列で曜日を表現している様子がわかるでしょうか。これをswitch文で判定し、分岐先で「休日」か「平日」かを決定しています。実行結果からも、Javaのswitch文では文字列でも数値と変わらず分岐できることがわかるでしょう。

defaultを記述している理由については、少し補足が必要かもしれません。常識的に考えれば曜日は7種類しか存在しませんが、文字列の変数には曜日以外にもさまざまな値を格納できます。そのため、ここではdefaultによって、文字列を曜日として判定できないケースにも備えているのです。

switch文で文字列を使う場合の注意点

switch文で文字列の値を判定するプログラムには、間違えやすいため注意が必要な面があります。

次のサンプルコードを眺めてみてください。これは、1つ前のサンプルコードとまったく同じ処理を行なおうとしたものですが、期待と異なる実行結果になってしまっています。どこに間違いがあるか、見つけられるでしょうか。

サンプルコード:

public class Main {
    public static void main(String[] args) {
        var value = "Saturday";
        var result = "";

        switch (value) {
            case "Sunday", "Satarday" -> {
                result = "休日";
            }
            case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" -> {
                result = "平日";
            }
            default -> {
                result = "不明な曜日";
            }
        }

        System.out.println("結果:" + result);
    }
}

実行結果:

結果:不明な曜日

実行結果から、switch文はdefaultに分岐したことがわかります。これは、文字列を判定した結果が、曜日を表す7つの値のどれとも一致しなかったということです。

そこで、文字列をくまなく確認すると、スペルミスに気付くでしょう。

case "Sunday", "Satarday" -> { // ← スペルミス

文字列にこのようなスペルミスがあっても、プログラムをコンパイルして実行することは可能です。そのため、原因を突き止めるのに時間がかかってしまうことも考えられます。

早い段階でスペルミスに気付き、効率良く修正できるようにするには、このあと紹介するように列挙型(enum)を活用するのも一つの方法です。

Javaのswitch文で列挙型を使用する

列挙型は、例えば曜日のように、あらかじめ種類が決まっている値を表すのに便利な型です。ここでは、列挙型の値で分岐するswitch文について説明します。

列挙型の値で分岐するswitch文の記法

列挙型によるswitch文の記法も、数値や文字列によるswitch文と大きく変わりません。上記で取り上げた曜日を文字列で判定するプログラムを、列挙型で書き換えてみましょう。

サンプルコード:

public class Main {
    enum DayOfWeek {
        SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
    }

    public static void main(String[] args) {
        var value = DayOfWeek.SATURDAY;
        var result = "";

        switch (value) {
            case SUNDAY, SATURDAY -> {
                result = "休日";
            }
            case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
                result = "平日";
            }
        }

        System.out.println("結果:" + result);
    }
}

実行結果:

結果:休日

プログラムの前半で、7つの曜日のいずれかを表す列挙型として「DayOfWeek」を定義しているのがわかるでしょうか。switch文では、この型の値を判定して分岐しています。

文字列によるswitch文には、スペルミスに気付きづらい問題がありました。これに対して列挙型では、値を正確に記述しなければコンパイルエラーが発生します。そのため、スペルミスのような単純な間違いは、実行前に取り除けるでしょう。

なお、このサンプルコードにはdefaultがありません。これは、列挙型によるswitch文では、すべてのcaseを文字どおり「列挙」できるためです。

switch文で列挙型を使うときのdefault

switch文で列挙型を用いる際は、すべての値をcaseで明示できるため、基本的にはdefaultを記述する必要がありません。しかし、defaultを利用すると役立つ場面もあります。

具体的には、次のようなケースです。

switch (value) {
    case SUNDAY, SATURDAY -> {
        result = "休日";
    }
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
        result = "平日";
    }
    default -> {
        throw new AssertionError("caseが不足しています!");
    }
}

ここでは、defaultに分岐したら例外を発生させています。これは、「もしdefaultに到達したら、何かの間違いだ」ということを表す書き方です。

とはいえ、少なくとも今のところは、このswitch文の制御がdefaultに到達することはないでしょう。しかし、将来的に列挙型の値が増えると想定される場合は、作業漏れを減らすのに役立ちます。

例えば、曜日を表す列挙型を、次のように曜日以外の日も表せるように拡張したくなるかもしれません。

enum DayOfWeek {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY,
    BIRTHDAY, HOLIDAY, TODAY // 将来的に追加されるかもしれない
}

このように列挙型の値を増やした場合、通常は同じものをswitch文のcaseにも追加する必要があります。その作業に漏れがあると、defaultのないswitch文では何も実行されず、ただ通過するだけになってしまうでしょう。

そこで役立つのが、上記のような例外を発生させるdefaultです。未知の値に対して例外が発生するため、まだcaseの追加が必要なswitch文が残っていることに早い段階で気付けるようになります。

なお、Javaの例外については下記の記事でも解説しているので、併せて参考にしてください。
Javaのtry-catchとは?例外処理の方法をサンプルコードで解説

Javaのswitch-caseを式として扱う

switch文は、switch-caseを「文」として扱う記法です。これに対し、Javaにはswitch-caseを「式」として扱う「switch式」という記法もあります。

switch式の記法

switch-caseによる判定結果を変数に格納することを考えてみましょう。switch文を使う場合は、例えば次のようになります。

var value = 3;
var result = "";

switch (value) {
    case 1, 2 -> result = "1または2";
    case 3, 4 -> result = "3または4";
    default -> result = "そのほか";
}

breakなしでシンプルに記述できてはいますが、結果を表す変数「result」の扱いにやや冗長な部分があります。

これは、switch式を用いて次のように書き直すことが可能です。

var value = 3;
var result = switch (value) {
    case 1, 2 -> "1または2";
    case 3, 4 -> "3または4";
    default -> "そのほか";
};

switch-caseを変数に直接代入するような、コンパクトな記法になっているのがわかるでしょうか。これにより、「result」には分岐先のcaseに応じた結果が代入されます。

このようなことが可能なのは、switch式ではswitch-case全体が値をもつためです。各caseの処理(「->」の右側)にも、代入などの「文」ではなく、値をもつ「式」が記述されている点に留意しましょう。

switch式の注意点

switch式には、分岐する可能性のあるすべての値を網羅的に記述しなければならないという制約があります。さもないと、最終的な値を決定できない場合が出てきてしまうためです。したがって、switch式には原則としてdefaultを書いておかなければなりません。

ただし、次のように列挙型のすべての値をcaseで明記している場合については、defaultは不要です。

var value = DayOfWeek.SATURDAY;
var result = switch (value) {
    case SUNDAY, SATURDAY -> "休日";
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "平日";
};

また、switch文と同様に、switch式から例外を発生させることも可能です。列挙型の値があとから増えるかもしれないときは、次のようにdefaultを記述して将来の変更に備えておくとよいでしょう。

var value = DayOfWeek.SATURDAY;
var result = switch (value) {
    case SUNDAY, SATURDAY -> "休日";
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "平日";
    default -> throw new AssertionError("caseが不足しています!");
};

Javaでの条件分岐はswitch文とswitch式でわかりやすくなる

switch-caseは、プログラムの流れを分岐させるための構文です。同様の概念はさまざまなプログラミング言語にみられますが、Javaでは通常のswitch文だけでなく、構文全体が値をもつswitch式も利用できます。

また、Javaのswitch文やswitch式では、数値だけでなく文字列や列挙型の値も分岐の条件として指定可能です。用途に合わせて適切な型を使用したり、フォール・スルーに頼らないbreakなしの記法を用いたりすることによって、プログラムは読みやすく理解しやすいものになるでしょう。

こうした工夫は、気付きづらい問題を早期に発見するためにも役立ちます。今回紹介した内容を、Javaによるプログラミングの質を高めるための参考にしてみてください。