1. 概要

このチュートリアルでは、switchステートメントとは何かとその使用方法を学習します。

switch ステートメントを使用すると、いくつかのネストされた if-else 構造を置き換えて、コードの読みやすさを向上させることができます。

Switch は時間の経過とともに進化し、特にJava5および7でサポートされる新しいタイプが追加されました。 また、進化を続けています。switch式はJava12で導入される可能性があります。

以下に、 switch ステートメントの使用、 break ステートメントの役割、switch引数/[の要件を示すコード例をいくつか示します。 X185X]case値とswitchステートメントのStringの比較。

例に移りましょう。

2. 使用例

たとえば、次のネストされたif-elseステートメントがあるとします。

public String exampleOfIF(String animal) {
    String result;
    if (animal.equals("DOG") || animal.equals("CAT")) {
        result = "domestic animal";
    } else if (animal.equals("TIGER")) {
        result = "wild animal";
    } else {
        result = "unknown animal";
    }
    return result;
}

上記のコードは見栄えが悪く、保守や推論が難しいでしょう。 読みやすさを向上させるために、ここでswitchステートメントを使用できます。

public String exampleOfSwitch(String animal) {
    String result;
    switch (animal) {
        case "DOG":
            result = "domestic animal"; 
            break;
        case "CAT":
            result = "domestic animal";
            break;
        case "TIGER":
            result = "wild animal";
            break;
        default:
            result = "unknown animal";
            break;
    }
    return result;
}

上に示したように、switch引数animalをいくつかのcase値と比較します。 case の値のいずれも引数と等しくない場合、defaultラベルの下のブロックが実行されます。

簡単に言うと、 break ステートメントは、switchステートメントを終了するために使用されます。

3. breakステートメント

実際のswitchステートメントのほとんどは、 case ブロックの1つだけを実行する必要があることを意味しますが、breakステートメントはを終了するために必要です。ブロックが完了した後、switch

break を書くのを忘れると、その下のブロックが実行されます。

これを示すために、 break ステートメントを省略し、各ブロックの出力をコンソールに追加しましょう。

public String forgetBreakInSwitch(String animal) {
    switch (animal) {
    case "DOG":
        System.out.println("domestic animal");
    default:
        System.out.println("unknown animal");
    }
}

このコードforgetBreakInSwitch “DOG”)、を実行し、出力をチェックして、すべてのブロックが実行されることを確認しましょう。

domestic animal
unknown animal

したがって、次のラベルの下のコードにパススルーする必要がない限り、注意して各ブロックの最後にbreakステートメントを追加する必要があります。

break が不要な唯一のブロックは最後のブロックですが、最後のブロックに break を追加すると、コードでエラーが発生しにくくなります。

この動作を利用して、 複数のcaseステートメントに対して同じコードを実行する場合は、breakを省略します。 最初の2つのケースをグループ化して、前のセクションの例を書き直してみましょう。

public String exampleOfSwitch(String animal) {
    String result;
    switch (animal) {
        case "DOG":
        case "CAT":
            result = "domestic animal";
            break;
        case "TIGER":
            result = "wild animal";
            break;
        default:
            result = "unknown animal";
            break;
    }
    return result;
}

4. switch引数とcase

次に、許可されるswitch引数とcase値のタイプ、それらの要件、およびswitchステートメントが文字列でどのように機能するかについて説明します。

4.1. データ型

switchステートメントのすべてのタイプのオブジェクトとプリミティブを比較することはできません。 スイッチは、4つのプリミティブとそのラッパー、および列挙型と文字列クラスでのみ機能します:

  • バイトおよびバイト
  • ショートおよびショート
  • intおよびInteger
  • charおよびCharacter
  • 列挙型

String typeは、Java7以降のswitchステートメントで使用できます。

enumタイプはJava5で導入され、それ以来switchステートメントで使用可能になっています。

Java 5以降、ラッパークラスも利用できるようになりました。

もちろん、switch引数とcaseの値は同じタイプである必要があります。

4.2. ヌル値なし

null値を引数としてswitchステートメントに渡すことはできません。 これを行うと、プログラムは最初のスイッチの例を使用して NullPointerException、をスローします。

@Test(expected=NullPointerException.class)
public void whenSwitchAgumentIsNull_thenNullPointerException() {
    String animal = null;
    Assert.assertEquals("domestic animal", s.exampleOfSwitch(animal));
}

もちろん、switchステートメントのcaseラベルに値としてnullを渡すこともできません。 これを行うと、コードはコンパイルされません。

4.3. コンパイル時定数としてのCase

DOGのケース値を変数dogに置き換えようとすると、dog変数をfinalとしてマークするまで、コードはコンパイルされません。 ]:

final String dog="DOG";
String cat="CAT";

switch (animal) {
case dog: //compiles
    result = "domestic animal";
case cat: //does not compile
    result = "feline"
}

4.4. 文字列比較

switch ステートメントが等式演算子を使用して文字列を比較した場合、新しい演算子で作成されたString引数Stringと比較できませんでした]ケース値を正しく。

幸い、 switch演算子は、内部でequals()メソッドを使用します

これをデモンストレーションしましょう:

@Test
public void whenCompareStrings_thenByEqual() {
    String animal = new String("DOG");
    assertEquals("domestic animal", s.exampleOfSwitch(animal));
}

5. switch

JDK 13 が利用可能になり、 JDK12で最初に導入された新機能の改良バージョンであるswitch式が提供されます。

これを有効にするには、 –enable-previewをコンパイラーに渡す必要があります。

5.1. 新しいスイッチ

数か月を切り替えると、新しいswitch式がどのようになるかを見てみましょう。

var result = switch(month) {
    case JANUARY, JUNE, JULY -> 3;
    case FEBRUARY, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER -> 1;
    case MARCH, MAY, APRIL, AUGUST -> 2;
    default -> 0; 
};

Month.JUNE のような値を送信すると、result3.に設定されます。

新しい構文では、 switch ステートメントで使用していたコロンの代わりに、->演算子が使用されていることに注意してください。 また、 break キーワードはありません:switch式はcaseに該当しません。

もう1つの追加は、コンマ区切りの基準を持つことができるという事実です。

5.2. 歩留まりキーワード

さらに進んで、コードブロックを使用して、式の右側で何が起こっているかをきめ細かく制御できる可能性があります。 このような場合、キーワードyieldを使用する必要があります。

var result = switch (month) {
    case JANUARY, JUNE, JULY -> 3;
    case FEBRUARY, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER -> 1;
    case MARCH, MAY, APRIL, AUGUST -> {
        int monthLength = month.toString().length();
        yield monthLength * 4;
    }
    default -> 0;
};

この例は少し恣意的ですが、ここでのポイントは、ここでJava言語の多くにアクセスできるということです。

5.3. switch式の内部に戻る

switchステートメントとswitch式の違いにより、 switchステートメント内から戻ることは可能ですが、内部から戻ることはできません。スイッチ式

次の例は完全に有効であり、コンパイルされます。

switch (month) {
    case JANUARY, JUNE, JULY -> { return 3; }
    default -> { return 0; }
}

ただし、次のコードは、囲んでいるスイッチ式の外側で return しようとしているため、コンパイルされません。

var result = switch (month) {
    case JANUARY, JUNE, JULY -> { return 3; }
    default -> { return 0; }
};

5.4. 網羅性

switch ステートメントを使用する場合、すべてのケースがカバーされているかどうかは実際には問題ではありません

たとえば、次のコードは完全に有効であり、コンパイルされます。

switch (month) { 
    case JANUARY, JUNE, JULY -> 3; 
    case FEBRUARY, SEPTEMBER -> 1;
}

ただし、 switch 式の場合、コンパイラーはすべての可能なケースがカバーされると主張します。 たとえば、次のコードスニペットは、デフォルトのケースがなく、考えられるすべてのケースがカバーされているわけではないため、コンパイルされません。

var result = switch (month) {
    case JANUARY, JUNE, JULY -> 3;
    case FEBRUARY, SEPTEMBER -> 1;
}

ただし、 switch 式は、次の例のように、考えられるすべてのケースがカバーされている場合に有効になります。

var result = switch (month) {
    case JANUARY, JUNE, JULY -> 3;
    case FEBRUARY, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER -> 1;
    case MARCH, MAY, APRIL, AUGUST -> 2;
}

上記のコードスニペットにはデフォルトのケースがないことに注意してください。 すべてのケースがカバーされている限り、switch式は有効です。

6. 結論

このチュートリアルでは、Javaでswitchステートメントを使用する際の微妙な点を学びました。 読みやすさと比較値の種類に基づいて、スイッチを使用するかどうかを決定できます。

switchステートメントは、事前定義されたセットに限られた数のオプションがある場合(例:曜日)に適しています。 そうしないと、新しい値が追加または削除されるたびにコードを変更する必要があり、実行できない可能性があります。 このような場合は、ポリモーフィズムなどの他のアプローチやコマンドなどの他のデザインパターンを検討する必要があります。

いつものように、完全なJDK8コードJDK13コードはGitHubで入手できます。