switch 内の各コード ブロックの後に、コンパイラが自動的に break ステートメントを配置しないのはなぜですか? 歴史的な理由ですか?複数のコード ブロックをいつ実行しますか?
17 に答える
次のように、複数のケースを同じコード ブロックに関連付けると便利な場合があります。
case 'A':
case 'B':
case 'C':
doSomething();
break;
case 'D':
case 'E':
doSomethingElse();
break;
など。ほんの一例です。
私の経験では、通常、「フォールスルー」して複数のコードブロックを 1 つのケースで実行するのは悪いスタイルですが、状況によってはそれを使用することもあります。
歴史的に、これはcase
が本質的に を定義していたためで、呼び出しのターゲット ポイントlabel
としても知られています。switch ステートメントとそれに関連するケースは、実際には、コード ストリームへの複数の潜在的なエントリ ポイントを持つ多方向分岐を表しています。goto
break
そうは言っても、ほとんどの場合、すべてのケースの最後に設定したいデフォルトの動作であることにほぼ無限の回数が注目されています。
Java は C から来ており、それが C の構文です。
複数の case ステートメントに 1 つの実行パスのみを持たせたい場合があります。以下は、月に何日あるかを示すサンプルです。
class SwitchDemo2 {
public static void main(String[] args) {
int month = 2;
int year = 2000;
int numDays = 0;
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
numDays = 31;
break;
case 4:
case 6:
case 9:
case 11:
numDays = 30;
break;
case 2:
if ( ((year % 4 == 0) && !(year % 100 == 0))
|| (year % 400 == 0) )
numDays = 29;
else
numDays = 28;
break;
default:
System.out.println("Invalid month.");
break;
}
System.out.println("Number of Days = " + numDays);
}
}
間違いだと思います。言語構造として、デフォルトと同じくらい簡単に使用できbreak
、代わりにfallthrough
キーワードを使用できます。私が書いたり読んだりしたコードのほとんどは、すべてのケースの後に中断しています。
ケースフォールスルーを使用すると、あらゆる種類の興味深いことができます。
たとえば、すべてのケースで特定のアクションを実行したいが、特定のケースではそのアクションに加えて何かを実行したいとします。フォールスルーで switch ステートメントを使用すると、非常に簡単になります。
switch (someValue)
{
case extendedActionValue:
// do extended action here, falls through to normal action
case normalActionValue:
case otherNormalActionValue:
// do normal action here
break;
}
もちろん、break
ケースの最後のステートメントを忘れて、予期しない動作を引き起こすのは簡単です。優れたコンパイラは、break ステートメントを省略すると警告を発します。
switch 内の各コード ブロックの後に、コンパイラが自動的に break ステートメントを配置しないのはなぜですか?
同じブロックを複数のケース (特殊なケースである可能性があります) に使用できるようにしたいという希望はさておき...
歴史的な理由ですか?複数のコード ブロックをいつ実行しますか?
goto
これは主に C との互換性のためのものであり、キーワードが地球を歩き回っていた昔からの古代のハックであることは間違いありません。もちろん、ダフのデバイスなど、いくつかの驚くべきことを可能にしますが、それが賛成か反対かは…せいぜい議論の余地があります。
歴史的記録に関する限り、Tony Hoareは、「構造化プログラミング」革命の1960年代にcaseステートメントを発明しました。Tonyのcaseステートメントは、ケースごとに複数のラベルをサポートし、悪臭を放つbreak
ステートメントなしで自動的に終了しました。明示的な要件break
は、BCPL / B/Cラインから出てきたものでした。デニス・リッチーは次のように書いています(ACM HOPL-II):
たとえば、BCPL switchonステートメントからエスケープするエンドケースは、1960年代に学習したときの言語には存在しなかったため、BおよびC switchステートメントからエスケープするためのbreakキーワードのオーバーロードは、意識的ではなく分岐進化によるものです。変化する。
break
私はBCPLに関する歴史的な著作を見つけることができませんでしたが、リッチーのコメントは、それが多かれ少なかれ歴史的な事故であったことを示唆しています。BCPLは後で問題を修正しましたが、おそらくRitchieとThompsonはUnixの発明に忙しくて、そのような詳細に悩まされることはありませんでした:-)
したがって、同じことを行うために複数のケースが必要な場合でも、コードを繰り返す必要はありません。
case THIS:
case THAT:
{
code;
break;
}
または、次のようなことができます:
case THIS:
{
do this;
}
case THAT:
{
do that;
}
カスケード方式で。
あなたが私に尋ねると、本当にバグ/混乱が起こりやすいです。
Java は C から派生したものであり、その遺産にはDuff's Deviceとして知られる手法が含まれています。break;
これは、ステートメントがない場合、制御が 1 つのケースから次のケースに移行するという事実に依存する最適化です。C が標準化されるまでに、そのようなコードは「野生」でたくさんあり、そのような構造を壊すために言語を変更するのは逆効果でした。
他の種類の数、月、数を簡単に区切ることができます。
これは、この場合よりも優れています。
public static void spanishNumbers(String span){
span = span.toLowerCase().replace(" ", "");
switch (span){
case "1":
case "jan": System.out.println("uno"); break;
case "2":
case "feb": System.out.println("dos"); break;
case "3":
case "mar": System.out.println("tres"); break;
case "4":
case "apr": System.out.println("cuatro"); break;
case "5":
case "may": System.out.println("cinco"); break;
case "6":
case "jun": System.out.println("seis"); break;
case "7":
case "jul": System.out.println("seite"); break;
case "8":
case "aug": System.out.println("ocho"); break;
case "9":
case "sep": System.out.println("nueve"); break;
case "10":
case "oct": System.out.println("diez"); break;
}
}
コンパイラによって自動ブレークが追加されないため、スイッチ/ケースを使用して1 <= a <= 3
、1 と 2 からブレーク ステートメントを削除するなどの条件をテストできます。
switch(a) {
case 1: //I'm between 1 and 3
case 2: //I'm between 1 and 3
case 3: //I'm between 1 and 3
break;
}
たとえば、同じコードを複数のブロックに記述することを避けながら、複数のブロックを分割して複数のブロックを制御できるようにするために、最初のブロックを通過させたい場合があるためです。他にもたくさんの理由があります。
私は現在break
、switch ステートメントで必要なプロジェクトに取り組んでいます。そうしないと、コードが機能しません。break
我慢してください。switch ステートメントで必要な理由の良い例を示します。
3 つの状態があるとします。1 つはユーザーが数値を入力するのを待つ状態、2 番目はそれを計算する状態、3 番目は合計を出力する状態です。
その場合、次のものがあります。
- State1 - ユーザーが数字を入力するのを待つ
- State2 - 合計を出力
- state3 - 合計を計算する
状態を見ると、正確な順序をstate1から開始し、次にstate3、最後にstate2にする必要があります。それ以外の場合は、合計を計算せずにユーザー入力のみを出力します。もう一度明確にするために、ユーザーが値を入力するのを待ってから、合計を計算して合計を出力します。
コード例を次に示します。
while(1){
switch(state){
case state1:
// Wait for user input code
state = state3; // Jump to state3
break;
case state2:
//Print the sum code
state = state3; // Jump to state3;
case state3:
// Calculate the sum code
state = wait; // Jump to state1
break;
}
}
を使用しない場合、 state1、 state2 、state3break
の順に実行されます。しかし、 を使用すると、このシナリオを回避し、state1 で開始し、次に state3、最後に state2 という正しい手順で注文できます。break
正確には、いくつかの巧妙な配置により、ブロックをカスケードで実行できるためです。