Die Idee hinter lokalen Variablen ist, dass sie nur innerhalb des begrenzten Bereichs existieren, für den sie benötigt werden. Daher sollte es wenig Grund zur Ungewissheit über den Wert geben, oder zumindest darüber, woher dieser Wert kommt. Ich könnte mir viele Fehler vorstellen, die durch einen Standardwert für lokale Variablen entstehen.
Betrachten Sie zum Beispiel den folgenden einfachen Code... ( Zur Veranschaulichung nehmen wir an, dass lokalen Variablen der angegebene Standardwert zugewiesen wird, wenn sie nicht ausdrücklich initialisiert werden )
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);
Schließlich ist alles gesagt und getan, unter der Annahme, dass der Compiler einen Standardwert von ' \0 ' zu letterGrade würde dieser Code in der vorliegenden Form ordnungsgemäß funktionieren. Was aber, wenn wir die else-Anweisung vergessen?
Ein Testlauf unseres Codes könnte zu folgendem Ergebnis führen
Enter grade
43
Your grade is
Dieses Ergebnis ist zwar zu erwarten, war aber sicher nicht die Absicht des Codierers. In der Tat wäre wahrscheinlich in der großen Mehrheit der Fälle (oder zumindest in einer beträchtlichen Anzahl davon) der Standardwert nicht der Gewünscht Wert, so dass der Standardwert in den allermeisten Fällen zu einem Fehler führen würde. Es ist sinnvoller, den Programmierer zu zwingen, einer lokalen Variablen einen Anfangswert zuzuweisen, bevor er sie verwendet, da die Fehlersuche durch das Vergessen der = 1
en for(int i = 1; i < 10; i++)
überwiegt bei weitem die Bequemlichkeit, die es mit sich bringt, die = 0
en for(int i; i < 10; i++)
.
Es stimmt, dass try-catch-finally-Blöcke ein wenig chaotisch werden können (aber es ist nicht wirklich eine Zwickmühle, wie das Zitat zu suggerieren scheint), wenn zum Beispiel ein Objekt eine geprüfte Ausnahme in seinem Konstruktor auslöst, aber aus dem einen oder anderen Grund etwas muss am Ende des Blocks in finally mit diesem Objekt gemacht werden. Ein perfektes Beispiel hierfür ist der Umgang mit Ressourcen, die geschlossen werden müssen.
Eine Möglichkeit, dies in der Vergangenheit zu handhaben, könnte folgendermaßen aussehen...
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();
}
Ab Java 7 ist dieser finally-Block jedoch nicht mehr notwendig, wenn man try-with-resources verwendet, etwa so.
try (Scanner s = new Scanner(new FileInputStream(new File("filename.txt")))) {
...
...
} catch(IOException e) {
System.out.println("different error message");
}
Allerdings funktioniert dies (wie der Name schon sagt) nur mit Ressourcen.
Und während das erste Beispiel ein bisschen eklig ist, spricht dies vielleicht mehr für die Art und Weise, wie try-catch-finally oder diese Klassen implementiert sind, als für lokale Variablen und deren Implementierung.
Es stimmt zwar, dass Felder mit einem Standardwert initialisiert werden, aber das ist etwas anderes. Wenn Sie zum Beispiel sagen, int[] arr = new int[10];
Sobald Sie dieses Array initialisiert haben, befindet sich das Objekt im Speicher an einer bestimmten Stelle. Nehmen wir für einen Moment an, dass es keine Standardwerte gibt, sondern dass der Anfangswert eine beliebige Folge von 1en und 0en ist, die sich gerade an dieser Speicherstelle befindet. Dies könnte in einer Reihe von Fällen zu nicht-deterministischem Verhalten führen.
Angenommen, wir haben...
int[] arr = new int[10];
if(arr[0] == 0)
System.out.println("Same.");
else
System.out.println("Not same.");
Es wäre durchaus möglich, dass Same.
in einem Durchgang angezeigt werden können und Not same.
in einem anderen angezeigt werden kann. Das Problem könnte noch gravierender werden, wenn man anfängt, von Referenzvariablen zu sprechen.
String[] s = new String[5];
Laut Definition sollte jedes Element von s auf einen String verweisen (oder null sein). Wenn der Anfangswert jedoch eine beliebige Folge von 0en und 1en ist, die zufällig an dieser Speicherstelle auftritt, gibt es nicht nur keine Garantie, dass man jedes Mal die gleichen Ergebnisse erhält, sondern auch keine Garantie, dass das Objekt s[0] auf etwas Sinnvolles zeigt (vorausgesetzt, es zeigt auf etwas Sinnvolles). es eine Zeichenfolge (vielleicht ist es ein Kaninchen, :p )! Dieser Mangel an Rücksicht auf den Typ würde so ziemlich allem widersprechen, was Java ausmacht. Während also Standardwerte für lokale Variablen bestenfalls als optional angesehen werden könnten, sind Standardwerte für Instanzvariablen eher ein Notwendigkeit .