3 Switch式

Java SE 12ではswitch式が導入されており、この式は(すべての式と同様に)単一の値として評価され、文で使用することができます。また、"矢印case"ラベルも導入され、これによりフォール・スルーを防ぐためのbreak文は必要なくなりました。この機能に対する開発者のフィードバックに基づいて、Java SE 13ではswitch式に変更が1つ導入されています。それらの値を指定するには、break文ではなく新しいyield文を使用してください。

注意:

これは、設計、仕様および実装は完了しているが、永続的でないプレビュー機能であり、将来のJDKリリースでは別の形式で存在するか、完全になくなる可能性があることを意味します。プレビュー機能が含まれているコードをコンパイルして実行するには、追加のコマンド行オプションを指定する必要があります。「プレビュー機能」を参照してください。switch式の設計に関する背景情報は、JEP 354を参照してください。

曜日の文字数を出力する次のswitch文について検討してみます。

public enum Day { SUNDAY, MONDAY, TUESDAY,
    WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; }

// ...

    int numLetters = 0;
    Day day = Day.WEDNESDAY;
    switch (day) {
        case MONDAY:
        case FRIDAY:
        case SUNDAY:
            numLetters = 6;
            break;
        case TUESDAY:
            numLetters = 7;
            break;
        case THURSDAY:
        case SATURDAY:
            numLetters = 8;
            break;
        case WEDNESDAY:
            numLetters = 9;
            break;
        default:
            throw new IllegalStateException("Invalid day: " + day);
    }
    System.out.println(numLetters);

曜日名の長さは、変数numLettersに格納するかわりに値を戻せた方が便利で、これはswitch式を使用して行うことができます。また、フォール・スルーを防ぐのに、記述が面倒で付け忘れがちなbreak文が必要がなくなれば、さらに便利です。これは、新しい種類のcaseラベルで実現できます。次のswitch式では、新しい種類のcaseラベルを使用して、曜日の文字数を出力します。

    Day day = Day.WEDNESDAY;    
    System.out.println(
        switch (day) {
            case MONDAY, FRIDAY, SUNDAY -> 6;
            case TUESDAY                -> 7;
            case THURSDAY, SATURDAY     -> 8;
            case WEDNESDAY              -> 9;
            default -> throw new IllegalStateException("Invalid day: " + day);
        }
    );    

新しい種類のcaseラベルの形式は次のとおりです。

case label_1, label_2, ..., label_n -> expression;|throw-statement;|block 

Javaランタイムが矢印の左側にある任意のラベルに一致すると、矢印の右側にあるコードが実行されて、フォール・スルーしません。つまり、switch式(または文)内の他のコードは実行されません。矢印の右側のコードが式である場合、その式の値はswitch式の値になります。

新しい種類のcaseラベルをswitch文で使用できます。次の例は最初の例と同様ですが、「コロンcase」ラベルのかわりに「矢印case」ラベルが使用されています。

    int numLetters = 0;
    Day day = Day.WEDNESDAY;
    switch (day) {
        case MONDAY, FRIDAY, SUNDAY -> numLetters = 6;
        case TUESDAY                -> numLetters = 7;
        case THURSDAY, SATURDAY     -> numLetters = 8;
        case WEDNESDAY              -> numLetters = 9;
        default -> throw new IllegalStateException("Invalid day: " + day);
    };
    System.out.println(numLetters);

「コロンcase」ラベルは、次のようにswitch式で使用できます。

    Day day = Day.WEDNESDAY;
    int numLetters = switch (day) {
        case MONDAY:
        case FRIDAY:
        case SUNDAY:
            System.out.println(6);
            yield 6;
        case TUESDAY:
            System.out.println(7);
            yield 7;
        case THURSDAY:
        case SATURDAY:
            System.out.println(8);
            yield 8;
        case WEDNESDAY:
            System.out.println(9);
            yield 9;
        default:
            throw new IllegalStateException("Invalid day: " + day);
    };
    System.out.println(numLetters);

Java SE 13ではyield文が導入されています。これは、1つの引数(caseラベルがswitch式で生成する値)を取ります。

yield文により、switch文とswitch式を容易に区別できるようになります。switch文(switch式ではない)は、break文のターゲットとすることができます。反対に、switch式(switch文ではない)は、yield文のターゲットとすることができます。

注意:

「矢印case」ラベルの使用をお薦めします。「コロンcase」ラベルの使用時は、break文またはyield文の挿入を忘れがちです。これを忘れると、コード内で思いがけないフォール・スルーが発生する場合があります。

「矢印case」ラベルで、複数の文または式でないコード、あるいはthrow文を指定するには、それらをブロック内に囲みます。caseラベルが生成する値をyield文で指定します。

    int numLetters = switch (day) {
        case MONDAY, FRIDAY, SUNDAY -> {
            System.out.println(6);
            yield 6;
        }
        case TUESDAY -> {
            System.out.println(7);
            yield 7;
        }
        case THURSDAY, SATURDAY -> {
            System.out.println(8);
            yield 8;
        }
        case WEDNESDAY -> {
            System.out.println(9);
            yield 9;
        }
        default -> {
            throw new IllegalStateException("Invalid day: " + day);
        }
    };