Javaスイッチ。
int key = 2;
switch (key) {
case 1:
int value = 1;
break;
case 2:
value = 2;
System.out.println(value);
break;
default:
break;
}
シナリオ1-key
が2の場合、値を2として正常に出力します。
シナリオ2-value = 2
のcase 2:
にコメントするとき、というローカル変数の値が初期化されていない可能性があると言います。
質問:
シナリオ1:実行フローがcase 1:
に行かない場合(key = 2
の場合)、値変数の型をint
としてどのように知るのか?
シナリオ2:コンパイラが値変数の型をint
として認識している場合、int value = 1;
のcase 1:
式にアクセスしている必要があります(宣言と初期化)。それからなぜvalue = 2
でcase 2:
にコメントしようとすると、ローカル変数値が初期化されていない可能性があります。
Switchステートメントは、基本的にスコープの点で奇妙です。 JLSのセクション6. から:
ブロック内のローカル変数宣言(§14.4)のスコープは、宣言が現れる残りのブロックであり、独自のイニシャライザーから始まり、ローカル変数宣言ステートメントの右側にさらに宣言子を含めます。
あなたの場合、case 2
はcase 1
と同じblockにあり、case 1
にもかかわらず、その後に表示されます決して実行されません...したがって、論理的に宣言を「実行」することはありませんが、ローカル変数はスコープ内にあり、writingで使用できます。 (初期化は可能ですが、宣言は実際には「実行可能」ではありません。)
value = 2;
割り当てをコメント化すると、コンパイラは参照している変数をまだ認識していますが、値を割り当てる実行パスを経由することはないため、エラーが発生します。明確に割り当てられていない他のローカル変数を読み取ろうとする場合。
他のケースで宣言されたローカル変数を使用することを強くお勧めしますnotあなたが見たように、それは非常に混乱したコードにつながります。 switchステートメントでローカル変数を導入するとき(めったにしないこと-ケースは非常に短く、理想的には短いはずです)、通常、新しいスコープを導入することを好みます。
case 1: {
int value = 1;
...
break;
}
case 2: {
int value = 2;
...
break;
}
これはより明確だと思います。
変数は(intとして)宣言されていますが、初期化されていません(初期値が割り当てられています)。次の行を考えてください:
int value = 1;
なので:
int value;
value = 1;
int value
部分は、コンパイル時にコンパイラに、intというvalueという変数があることを伝えます。 value = 1
部分はそれを初期化しますが、それは実行時に起こり、スイッチのそのブランチが入力されない場合はまったく起こりません。
宣言はコンパイル時に処理され、コードの実行フローに依存しません。
value
はswitchブロックのローカルスコープ内で宣言されているため、宣言のポイントからそのブロック内の任意の場所で使用できます。
JEP 325:Switch Expressions(Preview) の統合により、JDK-12早期アクセスビルドに。 Jonの答え -から見られる特定の変更があります
Local Variable Scope-スイッチケースのローカル変数は、ケース自体に対してローカルになりますswitchブロック全体ではなく。さらなる説明のためにDay
enumクラスを考慮した例(Jonが構文的に試みたものと同様):
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
// some another method implementation
Day day = Day.valueOf(scanner.next());
switch (day) {
case MONDAY,TUESDAY -> {
var temp = "mon-tue";
System.out.println(temp);
}
case WEDNESDAY,THURSDAY -> {
var temp = Date.from(Instant.now()); // same variable name 'temp'
System.out.println(temp);
}
default ->{
var temp = 0.04; // different types as well (not mandatory ofcourse)
System.out.println(temp);
}
}
Switch Expressions-変数に値を割り当ててそれを利用する場合、一度switch式を使用できます。例えば.
private static void useSwitchExpression() {
int key = 2;
int value = switch (key) {
case 1 -> 1;
case 2 -> 2;
default -> {break 0;}
};
System.out.println("value = " + value); // prints 'value = 2'
}
この説明が役立つ場合があります。
int id=1;
switch(id){
default:
boolean b= false; // all switch scope going down, because there is no scope tag
case 1:
b = false;
case 2:{
//String b= "test"; you can't declare scope here. because it's in the scope @top
b=true; // b is still accessible
}
case 3:{
boolean c= true; // case c scope only
b=true; // case 3 scope is whole switch
}
case 4:{
boolean c= false; // case 4 scope only
}
}
Java仕様:
https://docs.Oracle.com/javase/specs/jls/se12/html/jls-14.html#jls-14.11
ラベルの区切りによる突然の完了の場合は、ラベル付きステートメントの一般規則(§14.7)によって処理されます。
https://docs.Oracle.com/javase/specs/jls/se12/html/jls-14.html#jls-14.7
ラベル付きステートメント:
LabeledStatement:識別子:ステートメント
LabeledStatementNoShortIf:識別子:StatementNoShortIf
CおよびC++とは異なり、Javaプログラミング言語にはgotoステートメントがありません。識別子ステートメントラベルは、ラベル付きステートメント内のどこかに現れるbreak(§14.15)またはcontinue(§14.16)ステートメントで使用されます。
ラベル付きステートメントのラベルの範囲は、すぐに含まれるステートメントです。
つまり、ケース1、ケース2はswitchステートメント内のラベルです。 breakおよびcontinueステートメントはラベルに適用できます。
ラベルはステートメントのスコープを共有するため、ラベル内で定義されたすべての変数はswitchステートメントのスコープを共有します。