有名な絵画の英雄のように、あなたが分岐点に立っていると想像してください。左に行けば馬を失い、右に行けば知識が得られます。このような状況をどのようにプログラムすればよいでしょうか? おそらく、if-thenおよびif-then-else構造を使用してそのような選択を行うことはすでにご存知でしょう。
新しい機能にもかかわらず、列挙型を使用するアプローチはより柔軟であり、使用することをお勧めします。この列挙型は何度も再利用できます。
if (turn_left) {
System.out.println(«Коня потеряешь»);
}
if (turn_right) {
System.out.println(“Знания обретёшь”);
}
else
System.out.println(“Так и будешь стоять?”);
このようなトラックが 2 つではなく 10 つあった場合はどうなるでしょうか? 10個の量の中に「右へ」「少し左へ」「もう少し左へ」という道があるでしょうか?このバージョンでif-then-elseコードがどのように成長するか想像してみてください。
if (вариант1)
{… }
else if (вариант2)
{…}
…
else if (вариантN) ….
したがって、条件のフォークは 1 つではなく、複数、たとえば 10 個あります (ここで重要なのは、フォークの数が制限されているということです)。このような状況に備えて、特別な選択演算子であるswitch case javaがあります。
switch (ВыражениеДляВыбора) {
case (Значение1):
Код1;
break;
case (Значение2):
Код2;
break;
...
case (ЗначениеN):
КодN;
break;
default:
КодВыбораПоУмолчанию;
break;
}
ステートメント内の実行順序は次のとおりです。
- SelectionExpression が評価されます。次に、switch ステートメントは、結果の式を次の値と (リストされた順序で) 比較します。
- SelectExpression が Value と一致する場合、コロンに続くコードが実行されます。
- Breakコンストラクトが見つかった場合、制御は switch コマンドの外部に移されます。
- ExpressionForSelection と Values の間に一致が見つからない場合、制御は DefaultSelectionCode に移されます。
-
Java の switch 選択ステートメントの SelectionExpression タイプは、次のいずれかである必要があります。
- byte、short、char、int。
- それらのラッパーはByte、Short、Character、Integerです。
- 文字列(Java 7 以降)。
- 列挙 ( Enum )。
- デフォルトのブロックはオプションであり、SelectionExpression と Values が一致しない場合、アクションは実行されません。
- Break
break
はオプションです。これが存在しない場合、コードは最初のswitch ステートメントが見つかるまで、または最後まで実行を続けます (case ブロック内の値のさらなる比較は無視されます) 。 - 複数の選択オプションに対して同じコードを実行する必要がある場合は、重複を避けるために、連続するcaseブロックでその前に複数の対応する値を示します。
Java で switch ステートメントを使用する練習に移りましょう。
心配しないでください。理論はこれで終わりです。さらに例を見てみると、すべてがより明確になります。それでは始めましょう。太陽系の惑星に関する天文学の例を見てみましょう。最新の国際規制に従って、冥王星は除外されます(軌道の性質により)。私たちの惑星は太陽から見て、水星、金星、地球、火星、木星、土星、天王星、海王星の順序で位置していることを思い出してください。入力として惑星のシリアル番号 (太陽からの距離に対する相対値) を受け取り、出力としてこの惑星の大気の主な構成を List <String> の形式で与える Java メソッドを作成しましょう。いくつかの惑星は似たような大気組成を持っていることを思い出させてください。したがって、金星と火星には主に二酸化炭素が含まれており、木星と土星は水素とヘリウムで構成され、天王星と海王星には最後のペアのガスに加えてメタンも含まれています。私たちの役割:public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("No Atmosphere");
break;
case 2:
case 4: result.add("Carbon dioxide");
break;
case 3: result.add("Carbon dioxide");
result.add("Nitrogen");
result.add("Oxygen");
break;
case 5:
case 6: result.add("Hydrogen");
result.add("Helium");
break;
case 7:
case 8: result.add("Methane");
result.add("Hydrogen");
result.add("Helium");
break;
default:
break;
}
return result;
}
注意してください: 私たちは同じコードを同じ大気組成を持つ惑星と比較しました。そして、私たちは連続的な格構造を使用してこれを実現しました。したがって、私たちの故郷の惑星の大気の組成を取得したい場合は、パラメーター 3 を指定してメソッドを呼び出します。
getPlanetAtmosphere(3).
System.out.println(getPlanetAtmosphere(3)) вернет нам [Углекислый газ, Азот, Кислород].
Break を試してみるBreakステートメント をすべて削除するとどうなるでしょうか? 実際に試してみましょう:
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("No Atmosphere");
case 2:
case 4: result.add("Carbon dioxide");
case 3: result.add("Carbon dioxide");
result.add("Nitrogen");
result.add("Oxygen");
case 5:
case 6: result.add("Hydrogen");
result.add("Helium");
case 7:
case 8: result.add("Methane");
result.add("Hydrogen");
result.add("Helium");
default:
}
return result;
}
この方法の結果を出力するとSystem.out.println(getPlanetAtmosphere(3))
、私たちの故郷の惑星は生命にそれほど適していないことになります。それとも適していますか?自分で判断してください: [二酸化炭素、窒素、酸素、水素、ヘリウム、メタン、水素、ヘリウム]、 なぜこれが起こったのでしょうか? プログラムはすべてのケースを実行しました最初の一致の後、switch ブロックの終わりまで、
過剰な最適化ブレーク
ブレークディレクティブと選択オプションを 別の配置にしてメソッドを改善できることに注意してください。public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("No Atmosphere");
break;
case 3: result.add("Nitrogen");
result.add("Oxygen");
case 2:
case 4: result.add("Carbon dioxide");
break;
case 7:
case 8: result.add("Methane");
case 5:
case 6: result.add("Hydrogen");
result.add("Helium");
}
return result;
}
短く見えますね。ケースの順序を工夫して再グループ化することで、ステートメントの総数を減らしました。これで、各タイプのガスが 1 行のコードだけでリストに追加されます。メソッドの最後の例のリストは、作業を説明するためにのみ示されており、そのようなスタイルで記述することは強くお勧めできません。同様のコードの作成者 (さらにはサードパーティのプログラマ) がそれを保守する必要がある場合、選択ブロックの形成ロジックと Java switch ステートメントの実行可能コードを復元するのは非常に困難になります。
if との違い
if ステートメントとswitchステートメントは外観が似ています が、if ステートメントの場合、複数選択演算子 switch は特定の値に基づいて実行オプションの選択を行うことを忘れないでください。任意の論理式を指定できます。コードを設計するときは、この事実を考慮してください。Java のさまざまなバージョンにおけるスイッチの革新を詳しく見てみましょう。Java 7 での切り替え
Java 7 より前では、byte、short、char、および int プリミティブをスイッチの値として使用できました。列挙型と、上記のプリミティブ型 (Character、Byte、Short、Integer) のラッパーもサポートされました。しかし、多くの場合、Java スイッチ文字列の値を見つける必要があります。Java 6 では次のようになります。DayOfWeek day = DayOfWeek.fromValue("Thursday");
switch (day) {
case MONDAY:
System.out.println("Today is windy !");
break;
case THURSDAY:
System.out.println("Today is sunny !");
break;
case WEDNESDAY:
System.out.println("Today is rainy!");
break;
default:
System.out.println("Oooops, something wrong !");
そして列挙型:
public enum DayOfWeek {
MONDAY("Monday"),
THURSDAY("Thursday"),
WEDNESDAY("Wednesday"),
NOT_FOUND("Not found");
private final String value;
DayOfWeek(final String value) {
this.value = value;
}
public static DayOfWeek fromValue(String value) {
for (final DayOfWeek dayOfWeek : values()) {
if (dayOfWeek.value.equalsIgnoreCase(value)) {
return dayOfWeek;
}
}
return NOT_FOUND;
}
}
ただし、Java 7 以降では、スイッチの値として String 型を使用できるようになりました。
String day = "Thursday";
switch (day) {
case "Monday":
System.out.println("Today is windy !");
break;
case "Thursday":
System.out.println("Today is sunny !");
break;
case "Wednesday":
System.out.println("Today is rainy!");
break;
default:
System.out.println("Oooops, something wrong !");
}
Java 12 での切り替え
Java 12 では、パターン マッチングの Switch 式が改善されました。上記の例のように Switch を使用する場合、変数の値を設定するには、値を計算して指定された変数に割り当ててから、break を使用する必要がありました。int count = 2;
int value;
switch (count) {
case 1:
value = 12;
break;
case 2:
value = 32;
break;
case 3:
value = 52;
break;
default:
value = 0;
}
しかし、Java 12 の機能のおかげで、この式を次のように書き直すことができます。
int value = switch (count) {
case 1:
break 12;
case 2:
break 32;
case 3:
break 52;
default:
break 0;
};
変更点を少し見てみましょう。
-
以前に case ブロック内に変数値を設定した場合、switch ステートメント自体は何も返せなかったので、今回はそのような機会があり、switch を使用して値を直接返します。
-
以前は、break の右側には何も置くことができませんでしたが、現在はこれを return ステートメントとして使用して、スイッチの値を返します。コロン マークは、ステートメント ブロックへのエントリ ポイントを示します。つまり、別のラベルが見つかった場合でも、その時点から以下のすべてのコードの実行が開始されます。
その結果、マークからマークへのエンドツーエンドの遷移が発生し、これはフォールスルーとも呼ばれます。
int count = 2;
int value = switch (count) {
case 1 -> 12;
case 2 -> 32;
case 3 -> 52;
default -> 0;
};
コードがかなりシンプルになりましたね。そしてもう 1 つ: ラムダ演算子はコロンの典型的な類似物としても機能し、その後にいくつかの演算を含むブロック全体が存在します。
int count = 2;
int value = switch (count) {
case 1 -> {
//some computational operations...
break 12;
}
case 2 -> {
//some computational operations...
break 32;
}
case 3 -> {
//some computational operations...
break 52;
}
default -> {
//some computational operations...
break 0;
}
};
では、場合によっては戻り値が同じである場合はどうなるでしょうか? 実際には、いくつかの異なる値に対して同じケースがあることがわかりました。Java 12 の新機能を使用してこれを短縮する方法は次のとおりです。
int count = 2;
int value = switch (count) {
case 1, 3, 5 -> 12;
case 2, 4, 6 -> 52;
default -> 0;
};
Java 13 での切り替え
Java 13 では、スイッチが値を返す方法が変更されました。Java 12 で、switch ブロックの戻り値として機能するブレーク後の戻り値を記述した場合、今度は、 yield という単語を使用して値を返します。見てみよう:int value = switch (count) {
case 1:
yield 12;
case 2:
yield 32;
case 3:
yield 52;
default:
yield 0;
};
同時に、break を使用して Java 12 で書かれたコードはコンパイルされません (( Break は使用されますが、何も返す必要がない状況では使用されます。
合計
- if 構造でコードが乱雑になるのを避けるために、分岐が 3 つ以上ある場合はcaseステートメントを使用します。
- 特定の値に対応する各分岐の論理ブロック (case ブロック) をブレークコールで終了することを忘れないでください。
- いくつかのプリミティブ型に加えて、switch ステートメントではEnum 型とString型を式として 使用することもできます。
- デフォルトのブロックを覚えておいてください。計画外の選択値を処理するために使用します。
- パフォーマンスを最適化するには、最も一般的な選択肢を含むコード分岐を switch ブロックの先頭に移動します。
- ケース選択ブロックの末尾にあるブレークを削除するなどの「最適化」に夢中にならないでください。そのようなコードは理解しにくく、その結果、開発中のメンテナンスが困難になります。
GO TO FULL VERSION