Java : switch文ではなくswitch式を使おう

switch文を使って break を書き忘れる…意外とあるあるだと思います。
そんなswitch文を改善した、switch式 がJava 14から追加されました。

switch式 を使うことで、break文の書き忘れという単純なミスから解放されます。
本記事では、そんな switch式 の基本的な使い方をご紹介します。


概要

あらゆる式と同様、switch式は1つの値に評価され、文での使用が可能です。
フォール・スルーを防ぐためのbreak文が不要になるcase L ->ラベルを使用できます。switch式の値の指定には、yield文を使用します。

switch式は、Java 14から正式に言語仕様に追加されました。
上記のリンクは、公式ドキュメントによるswitch式の紹介です。一読することをおすすめします。

それではswitch文とswitch式を簡単に見比べてみましょう。
まずは従来のswitchです。

valueパラメータで条件分岐させて、出力する内容を変えています。

public void main() {

    func(1); // いち
    func(2); // に
    func(3); // さん
    func(4); // それ以外
}

public void func(int value) {

    switch (value) {
        case 1:
            System.out.println("いち");
            break;
        case 2:
            System.out.println("に");
            break;
        case 3:
            System.out.println("さん");
            break;
        default:
            System.out.println("それ以外");
    }
}

switch の各ケース処理には break文が必要となりますね。

次は switchです。

public void main() {

    func(1); // いち
    func(2); // に
    func(3); // さん
    func(4); // それ以外
}

public void func(int value) {

    switch (value) {
        case 1 -> {
            System.out.println("いち");
        }
        case 2 -> {
            System.out.println("に");
        }
        case 3 -> {
            System.out.println("さん");
        }
        default -> {
            System.out.println("それ以外");
        }
    }
}

caseラベルの後ろが、コロン ":" の代わりに "->" となります。
各ケースの処理は { ... } というブロックで囲まれます。

// switch文
case 1:
    System.out.println("いち");
    break;
// switch式
case 1 -> {
    System.out.println("いち");
}

ラムダ式を使ったことのあるかたはピンとくるかもしれません。
{ ... } ブロックは if文でも使われていますし、スコープの範囲もより分かりやすく、コードの可読性もよくなったと思います。

そして、switch式では break文は不要となります。
break文の書き忘れが、言語仕様的になくなるわけですね。(すばらしい)

switch式の特徴

{...} ブロック

switchは、caseラベルから break文までが各ケースの処理の範囲でした。

switchでは break文の代わりに、{ ... } ブロックで処理の範囲(スコープ)を明確にできます。
break文は不要です。

public void main() {

    func(1); // いち
    func(2); // に
    func(3); // さん
    func(4); // それ以外
}

public void func(int value) {

    switch (value) {
        case 1 -> {
            System.out.println("いち");
        }
        case 2 -> {
            System.out.println("に");
        }
        case 3 -> {
            System.out.println("さん");
        }
        default -> {
            System.out.println("それ以外");
        }
    }
}

もしくは、単文の処理であればカッコを省略できます。(もちろんbreakも不要です)

public void func(int value) {

    switch (value) {
        case 1 -> System.out.println("いち");
        case 2 -> System.out.println("に");
        case 3 -> System.out.println("さん");
        default -> System.out.println("それ以外");
    }
}

複数のケースを1つの処理にまとめる

switchでは、意図的にbreak文を省略して複数のケースの処理をまとめる、ということができました。

※switchの例です。

public void main() {

    func(1); // いち、に、さん
    func(2); // いち、に、さん
    func(3); // いち、に、さん
    func(4); // よん
    func(5); // ご
    func(6); // それ以外
}

public void func(int value) {

    switch (value) {
        case 1:
        case 2:
        case 3:
            System.out.println("いち、に、さん");
            break;
        case 4:
            System.out.println("よん");
            break;
        case 5:
            System.out.println("ご");
            break;
        default:
            System.out.println("それ以外");
    }
}

そんな場合でも大丈夫です。
switchでも複数ケースをまとめることができます。

public void func(int value) {

    switch (value) {
        case 1, 2, 3 -> System.out.println("いち、に、さん");
        case 4 -> System.out.println("よん");
        case 5 -> System.out.println("ご");
        default -> System.out.println("それ以外");
    }
}

カンマ "," で複数の条件をcaseに指定できます。

switch式は、その名のとおりの特徴を持ちます。
とは、例えば

i + 2

i < 100

などです。

式は結果としての値を持ちます。
その値は代入式で変数に代入できます。

int a = i + 2;

switch式も同じように、代入式の右辺にを置くことができます。
つまり、switch式は値を返すことができます。

public void main() {

    func(1); // いち
    func(2); // に
    func(3); // さん
    func(4); // それ以外
}

public void func(int value) {

    final String result = switch (value) {
        case 1 -> {
            yield "いち";
        }
        case 2 -> {
            yield "に";
        }
        case 3 -> {
            yield "さん";
        }
        default -> {
            yield "それ以外";
        }
    };

    System.out.println(result);
}

値を返すには yield キーワードを使います。
もちろん、値を返す switch式で yield を書き忘れるとコンパイルエラーとなります。
書き忘れは発生しません。

もしくはブロックを省略すると、yield も省略できます。

public void func(int value) {

    final String result = switch (value) {
        case 1 -> "いち";
        case 2 -> "に";
        case 3 -> "さん";
        default -> "それ以外";
    };

    System.out.println(result);
}

まとめ

switch文と switch式の大きな違いは、break文が必要かどうかです。

break文は、書き忘れという単純なコーディングミスを引き起こしやすい、と個人的には思います。
そんな break文が不要となる switch式は、それだけで有用です。

さらに値も返せて便利です。特にデメリットもありません。

もし Java 14 以降を使っているのあれば、switch文の代わりに switch式 を使うことをおすすめします。


関連記事

ページの先頭へ