ローカル変数の背後にある考え方は、それらが必要な限られた範囲内にのみ存在するということです。そのため、値、または少なくともその値がどこから来ているかについて不確実な理由はほとんどないはずです。ローカル変数のデフォルト値が原因で多くのエラーが発生することは想像に難くありませんでした。
たとえば、次の単純なコードを考えてみましょう... (明示的に初期化されていない場合、明示的にローカル変数に指定されたデフォルト値が割り当てられていることをデモンストレーションの目的で仮定します)
System.out.println("Enter grade");
int grade = new Scanner(System.in).nextInt(); // I won't bother with exception handling here, to cut down on lines.
char letterGrade; // Let us assume the default value for a char is '\0'
if (grade >= 90)
letterGrade = 'A';
else if (grade >= 80)
letterGrade = 'B';
else if (grade >= 70)
letterGrade = 'C';
else if (grade >= 60)
letterGrade = 'D';
else
letterGrade = 'F';
System.out.println("Your grade is " + letterGrade);
結局のところ、コンパイラがデフォルト値の '\0' を letterGradeに割り当てたと仮定すると、書かれているこのコードは適切に機能します。しかし、else ステートメントを忘れたらどうなるでしょうか。
コードをテスト実行すると、次のようになる可能性があります
Enter grade
43
Your grade is
この結果は、当然のことながら、コーダーの意図によるものではありませんでした。実際、おそらく大多数の場合 (または少なくともかなりの数)、既定値は目的の値ではないため、ほとんどの場合、既定値はエラーになります。ローカル変数を使用する前に、ローカル変数に初期値を割り当てるようコーダーに強制する方が理にかなっています。これは、 in を忘れることによって引き起こされるデバッグの悲しみが、= 1
inをfor(int i = 1; i < 10; i++)
含める必要がないという便利さをはるかに上回るためです。= 0
for(int i; i < 10; i++)
try-catch-finally ブロックが少し乱雑になる可能性があることは事実です (ただし、引用が示唆しているように、実際には catch-22 ではありません)。何らかの理由で、finally のブロックの最後でこのオブジェクトに対して何かを行う必要があります。これの完璧な例は、閉じる必要があるリソースを扱う場合です。
過去にこれを処理する1つの方法は次のようになるかもしれません...
Scanner s = null; // Declared and initialized to null outside the block. This gives us the needed scope, and an initial value.
try {
s = new Scanner(new FileInputStream(new File("filename.txt")));
int someInt = s.nextInt();
} catch (InputMismatchException e) {
System.out.println("Some error message");
} catch (IOException e) {
System.out.println("different error message");
} finally {
if (s != null) // In case exception during initialization prevents assignment of new non-null value to s.
s.close();
}
ただし、Java 7 の時点では、try-with-resources などを使用すると、この finally ブロックは不要になりました。
try (Scanner s = new Scanner(new FileInputStream(new File("filename.txt")))) {
...
...
} catch(IOException e) {
System.out.println("different error message");
}
つまり、(名前が示すように) これはリソースでのみ機能します。
前者の例は少し厄介ですが、これはローカル変数とその実装方法よりも、try-catch-finally やこれらのクラスの実装方法に関係している可能性があります。
フィールドがデフォルト値に初期化されるのは事実ですが、これは少し異なります。たとえば、int[] arr = new int[10];
この配列を初期化するとすぐに、オブジェクトはメモリ内の特定の場所に存在します。少しの間、デフォルト値はないと仮定しましょう。代わりに、初期値は、その時点でそのメモリ位置にたまたまある一連の 1 と 0 です。これにより、多くの場合、非決定的な動作が発生する可能性があります。
私たちが持っているとしましょう...
int[] arr = new int[10];
if(arr[0] == 0)
System.out.println("Same.");
else
System.out.println("Not same.");
Same.
ある実行で表示され、別の実行で表示される可能性Not same.
は十分にあります。参照変数について話し始めると、問題はさらに深刻になる可能性があります。
String[] s = new String[5];
定義によれば、s の各要素は String を指す (または null である) 必要があります。ただし、初期値がこのメモリ位置で発生する一連の 0 と 1 である場合、毎回同じ結果が得られるという保証がないだけでなく、オブジェクト s[0] が指すという保証もありません。 to (意味のあるものを指していると仮定して) 文字列でさえあります (おそらくそれはうさぎです, :p )! この型への関心の欠如は、Java を Java にするほとんどすべてのものに直面することになります。したがって、ローカル変数のデフォルト値を持つことはせいぜいオプションと見なされる可能性がありますが、インスタンス変数のデフォルト値を持つことは必要に近いものです。