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.

67voto

Warrior Punkte 38697

Lokale Variablen werden meist deklariert, um eine Berechnung durchzuführen. Es ist also die Entscheidung des Programmierers, den Wert der Variable festzulegen, und sie sollte keinen Standardwert annehmen.

Wenn der Programmierer versehentlich eine lokale Variable nicht initialisiert hat und sie einen Standardwert annimmt, könnte die Ausgabe ein unerwarteter Wert sein. Bei lokalen Variablen fordert der Compiler den Programmierer daher auf, sie mit einem Wert zu initialisieren, bevor er auf die Variable zugreift, um die Verwendung nicht definierter Werte zu vermeiden.

24voto

Rob Kennedy Punkte 158781

Das "Problem", auf das Sie verweisen scheint diese Situation zu beschreiben:

SomeObject so;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  so.CleanUp(); // Compiler error here
}

Der Kommentator bemängelt, dass der Compiler die Zeile in der finally Abschnitt und behauptet, dass so könnte nicht initialisiert sein. Der Kommentar erwähnt dann eine andere Art, den Code zu schreiben, wahrscheinlich so etwas wie dies:

// Do some work here ...
SomeObject so = new SomeObject();
try {
  so.DoUsefulThings();
} finally {
  so.CleanUp();
}

Der Kommentator ist mit dieser Lösung unglücklich, weil der Compiler dann sagt, dass der Code "innerhalb eines Try" stehen muss. Ich vermute, das bedeutet, dass ein Teil des Codes eine Ausnahme auslösen kann, die nicht mehr behandelt wird. Ich bin mir nicht sicher. Keine der beiden Versionen meines Codes behandelt Ausnahmen, also sollte alles, was mit Ausnahmen zu tun hat, in der ersten Version genauso funktionieren wie in der zweiten.

Wie auch immer, diese zweite Version des Codes ist die richtig Art und Weise, es zu schreiben. In der ersten Version war die Fehlermeldung des Compilers korrekt. Die so Variable möglicherweise nicht initialisiert ist. Insbesondere, wenn die SomeObject Konstruktor scheitert, so wird nicht initialisiert, so dass es ein Fehler ist, zu versuchen, die so.CleanUp . Geben Sie immer die try Abschnitt nach Sie haben die Ressource erworben, die die finally Der Abschnitt ist abgeschlossen.

Le site try - finally Block nach dem so Initialisierung ist vorhanden nur zum Schutz der SomeObject Instanz, um sicherzustellen, dass es bereinigt wird, egal was sonst passiert. Wenn es andere Dinge, die laufen müssen, aber sie haben nichts damit zu tun, ob die SomeObject Instanz Eigentum zugewiesen wurde, dann sollten sie in eine andere try - finally Block, wahrscheinlich einen, der den von mir gezeigten umschließt.

Die manuelle Zuweisung von Variablen vor ihrer Verwendung führt nicht zu echten Problemen. Es führt nur zu kleineren Schwierigkeiten, aber Ihr Code wird dadurch besser. Sie werden Variablen mit einem begrenzteren Anwendungsbereich haben, und try - finally Blöcke, die nicht versuchen, zu viel zu schützen.

Wenn lokale Variablen Standardwerte haben, dann so im ersten Beispiel wäre es gewesen null . Das hätte nicht wirklich etwas gelöst. Anstatt einen Kompilierfehler in der finally Block, hätten Sie einen NullPointerException die dort lauern könnten ausblenden welche andere Ausnahme auch immer in dem Abschnitt "Do some work here" des Codes auftreten könnte. (Oder machen Sie Ausnahmen in finally Abschnitte automatisch mit der vorherigen Ausnahme verkettet? Ich weiß es nicht mehr. Selbst wenn, würden Sie eine zusätzliche Ausnahme in den Weg der eigentlichen haben.)

12voto

Bill K Punkte 61074

Die eigentliche Antwort auf Ihre Frage ist, dass Methodenvariablen instanziiert werden, indem dem Stapelzeiger einfach eine Zahl hinzugefügt wird. Sie auf Null zu setzen, wäre ein zusätzlicher Schritt. Bei Klassenvariablen werden sie in den initialisierten Speicher auf dem Heap gelegt.

Warum nicht einen Schritt weiter gehen? Treten Sie einen Schritt zurück - niemand hat erwähnt, dass die "Warnung" in diesem Fall eine sehr gute Sache ist.

Sie sollten Ihre Variable niemals beim ersten Durchlauf (wenn Sie sie zum ersten Mal kodieren) auf Null oder Null initialisieren. Weisen Sie ihr entweder den tatsächlichen Wert zu oder lassen Sie sie ganz weg, denn wenn Sie das nicht tun, kann Java Ihnen sagen, wann Sie wirklich Mist gebaut haben. Nehmen Sie Die Antwort von Electric Monk als ein großartiges Beispiel. Im ersten Fall ist es tatsächlich erstaunlich nützlich, dass es Ihnen sagt, dass, wenn die try() fehlschlägt, weil der Konstruktor von SomeObject eine Ausnahme ausgelöst hat, Sie mit einer NPE in der schließlich. Wenn der Konstruktor keine Ausnahme auslösen kann, sollte er nicht in der try-Datei stehen.

Diese Warnung ist ein großartiger Multi-Pfad-Prüfer für schlechte Programmierer, der mich davor bewahrt hat, dummes Zeug zu machen, da er jeden Pfad überprüft und sicherstellt, dass, wenn man die Variable in einem Pfad verwendet, man sie auch in jedem Pfad initialisieren muss, der dazu führt. Ich initialisiere jetzt nie explizit Variablen, bis ich feststelle, dass es das Richtige ist.

Ist es nicht außerdem besser, explizit "int size=0" zu sagen, als "int size" und den nächsten Programmierer herausfinden zu lassen, dass Sie beabsichtigen, es auf Null zu setzen?

Auf der anderen Seite fällt mir kein einziger triftiger Grund ein, warum der Compiler alle nicht initialisierten Variablen mit 0 initialisieren sollte.

12voto

Electric Monk Punkte 2160

Darüber hinaus könnte im folgenden Beispiel eine Ausnahme innerhalb der SomeObject-Konstruktion ausgelöst worden sein. In diesem Fall wäre die Variable 'so' null und der Aufruf von CleanUp würde eine NullPointerException auslösen

SomeObject so;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  so.CleanUp(); // Compiler error here
}

Ich tendiere zu folgendem Vorgehen:

SomeObject so = null;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  if (so != null) {
     so.CleanUp(); // safe
  }
}

12voto

Adeel Ansari Punkte 38973

Beachten Sie, dass die endgültigen Instanz-/Mitgliedsvariablen standardmäßig nicht initialisiert werden. Denn diese sind endgültig und können im Programm nicht mehr geändert werden. Das ist der Grund dafür, dass Java keinen Standardwert für sie vorgibt und den Programmierer zwingt, sie zu initialisieren.

Andererseits können nicht-finale Mitgliedsvariablen später geändert werden. Daher lässt der Compiler sie nicht uninitialisiert bleiben, eben weil sie später geändert werden können. Was die lokalen Variablen betrifft, so ist ihr Anwendungsbereich viel enger, und der Compiler weiß, wann sie verwendet werden. Daher ist es sinnvoll, den Programmierer zu zwingen, die Variable zu initialisieren.

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