`s

`switch`文 の Java

2個の演習

`switch`文について

_if/else_文と同じように、switch文を使うと、条件に応じてコードを実行することで、プログラムの流れを変えられます。 違いは、switch文では、プリミティブ型または文字列の式の値を、あらかじめ定義された定数値としか比較できないという点です。

switch文を使うときには、いくつかのキーワードが役立ちます。

  • switch: このキーワードで、switchの構造を宣言します。 そのあとには、結果を変化させる式または変数を書きます。
  • case: これは、結果として取りうる複数の可能性を宣言するために使います。
  • break: breakキーワードは、意図した流れの最後でswitchの実行を止めるためにとても役立ちます。 これを忘れると、プログラムはそのまま続けて実行され、予期しない結果になることがあります。
  • default: 名前のとおり、式の結果がほかのどのcaseにも一致しないときの既定の結果として使います。

最も単純な場合、プリミティブ型または文字列の式を評価し、その値に基づいて判断を下します。 たとえば、次のとおりです。

String direction = getDirection();
switch (direction) {
    case "left":
        goLeft();
        break;
    case "right":
        goRight();
        break;
    default:
        // otherwise
        markTime();
        break;
}

Java 14以降(それ以前のJava 12と13ではプレビューとして利用できました)では、「強化された」switchの実装を使えます。

  1. 1つのcaseに複数の値を指定できます。 従来のswitch文では、フォールスルーを使えます。次の例では、case 1とcase 3が同じ処理を実行します。 これは、case 1がbreakキーワードを使っていないためです。

    switch (number) {
        case 1:
        case 3:
            // do same stuff
            break;
        case 2:
            // do different stuff
            break;
        // (...)
    }
    

    強化されたswitch expressionでは、1つのcaseに直接複数の値を指定できます。 次の例を見てください。

    switch (number) {
        case 1, 3:
            // do stuff
            break;
        case 2:
            // do other stuff
            break;
        // (...)
    }
    
  2. これで、switch-statementまたはswitch expressionを書けるようになりました。 両者の違いは何でしょうか? 基本的に、文は厳密なロジックを前提とし、式は値を返すことができます。 次のように書く代わりに、

    String result = "";
    switch (expression) {
        case "bob":
            result = "bob";
            break;
        // (...)
    }
    

    このように書けます。

    String result = switch (expression) {
        case "bob":
            yield "bob";
        // (...)
    }
    

    yieldはreturnと同じように働きますが、switch式のためのものです。 yieldは式を終了させるので、ここではbreakは必要ありません。

  3. _switch文_と_switch式_のもう一つの違いは、switch式_では必ず_すべてのケースを網羅しなければならないことです。 すべての取りうる値にcaseを用意するか、defaultケースを使うかのどちらかです。

  4. :の代わりに->を使えます。 ->を使うと、breakキーワードを書かなくて済みます。 どちらの記法も使えますが、1つのswitchの中ではどちらか一方だけを使わなければなりません。

     switch(expression) {
         case 1 -> yield "one"
         case 2 -> yield "two"
         default: yield "other number" // Removing this will result in a compile error
     }
    
  5. スコープです。 従来のswitchでは、switch全体でスコープが1つしかないため、そのスコープに起因する予期しない動作が起こることがあります。

     switch(expression) {
         case 1:
             String message = "something";
             break;
         case 2:
             String message = "anything";
             break;
         // (...)
     }
    

    この例が動作しないのは、switchの中でmessageが2回宣言されているからです。 次のようにすれば解決できます。

     switch (expression) {
         case 1: {
             String message = "something";
             break;
         }
         case 2: {
             String message = "anything";
             break;
         }
         // (...)
     }
    

    {}がcaseのスコープを区切っているからです。 ただし、{}は必須ではないので直感的とは言えません。 一方、新しい->記法を使う場合は、そのあとに、単一の文または式、throw文、{}ブロックのいずれかを必ず続けなければなりません。 もう混乱することはありません!

強化されたswitchの詳細については、こちらの記事とこちらの記事、そして公式のOracleのドキュメントを参照してください。

さらに、Java 21ではGuarded Patternsという機能が追加され、caseラベル自体でチェックを行えるようになりました。

String dayOfMonth = getDayOfMonth();
String day = "";
return switch (day) {
    case "Tuesday" when dayOfMonth == 13 -> "Forbidden day!!";
    case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" -> "Week day";
    case "Saturday", "Sunday" -> "Weekend";
    default -> "Unknown";
};

Java 21のswitch式についての詳細は、こちらのブログで確認できます。

GitHubで編集 リンクは新しいウィンドウまたはタブで開きます

`switch`文を学習する