114 Stimmen

Warum werden lokale Variablen in Java nicht initialisiert?

Gab es einen Grund, warum die Entwickler von Java der Meinung waren, dass lokalen Variablen kein Standardwert zugewiesen werden sollte? Im Ernst: Wenn Instanzvariablen ein Standardwert zugewiesen werden kann, warum können wir das dann nicht auch für lokale Variablen tun?

Und es führt auch zu Problemen, wie in dieser Kommentar zu einem Blogeintrag :

Nun, diese Regel ist sehr frustrierend, wenn man versucht, eine Ressource in einem Endblock zu schließen. Wenn ich die Ressource innerhalb eines Try-Blocks instanziiere, aber versuche, sie innerhalb des Finally-Blocks zu schließen, erhalte ich diesen Fehler. Wenn ich die Instanziierung außerhalb des Try-Blocks verschiebe, erhalte ich eine weitere Fehlermeldung, die besagt, dass die Instanziierung innerhalb eines Try-Blocks erfolgen muss.

Sehr frustrierend.

6voto

T.J. Crowder Punkte 948310

Für mich ist die Grund läuft auf Folgendes hinaus: Der Zweck von lokalen Variablen ist ein anderer als der von Instanzvariablen. Lokale Variablen sind dazu da, um als Teil einer Berechnung verwendet zu werden; Instanzvariablen sind dazu da, um einen Zustand zu enthalten. Wenn Sie eine lokale Variable verwenden, ohne ihr einen Wert zuzuweisen, ist das mit Sicherheit ein logischer Fehler.

Abgesehen davon könnte ich mich durchaus dafür einsetzen, dass Instanzvariablen immer explizit initialisiert werden; der Fehler würde bei jedem Konstruktor auftreten, dessen Ergebnis eine nicht initialisierte Instanzvariable zulässt (z.B. nicht bei der Deklaration und nicht im Konstruktor initialisiert). Aber das ist nicht die Entscheidung, die Gosling und andere in den frühen 90er Jahren getroffen haben, also sind wir hier. (Und ich behaupte nicht, dass sie die falsche Entscheidung getroffen haben).

Ich könnte pas hinter der Vorgabe lokaler Variablen zu stehen, obwohl. Ja, wir sollten uns nicht darauf verlassen, dass Compiler unsere Logik doppelt überprüfen, und das tut man auch nicht, aber es ist trotzdem praktisch, wenn der Compiler einen erwischt :-)

4voto

starblue Punkte 53167

Es ist effizienter, Variablen nicht zu initialisieren, und im Fall von lokalen Variablen ist es sicher, dies zu tun, da die Initialisierung vom Compiler verfolgt werden kann.

In den Fällen, in denen eine Variable initialisiert werden muss, können Sie dies jederzeit selbst tun, so dass dies kein Problem darstellt.

4voto

mmx Punkte 400975

Ich denke, der Hauptzweck bestand darin, die Ähnlichkeit mit C/C++ zu erhalten. Der Compiler erkennt jedoch die Verwendung nicht initialisierter Variablen und warnt Sie davor, was das Problem auf ein Minimum reduziert. Aus Sicht der Leistung ist es etwas schneller, nicht initialisierte Variablen zu deklarieren, da der Compiler keine Zuweisungsanweisung schreiben muss, selbst wenn Sie den Wert der Variablen in der nächsten Anweisung überschreiben.

3voto

kumquatfelafel Punkte 41

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 .

1voto

Abhinav Chauhan Punkte 1130

Wenn ich mich nicht irre, könnte ein weiterer Grund sein :

Das Zuweisen eines Standardwerts für eine Mitgliedsvariable ist Teil des Klassenladens

Das Laden von Klassen ist in Java eine Sache der Laufzeit, d.h. wenn Sie ein Objekt erstellen, wird die Klasse mit Class Loading geladen. Nur Mitgliedsvariablen werden mit einem Standardwert initialisiert.

Die JVM nimmt sich nicht die Zeit, den lokalen Variablen einen Standardwert zu geben, da einige Methoden nie aufgerufen werden, da ein Methodenaufruf bedingt sein kann. Warum also Zeit aufwenden, um ihnen einen Standardwert zu geben und die Leistung zu verringern, wenn diese Standardwerte nie verwendet werden? Wenn man ihnen einen Standardwert gibt, bedeutet das auch, dass man sie zuerst erstellen muss, d.h. beim Laden der Klasse, und warum sollte man bei der Erstellung Speicher verschwenden, wenn sie nicht verwendet werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X