33 Stimmen

Warum muss die lokale Variable in einer erweiterten for-Schleife lokal sein?

Según la Java Sprachspezifikation, § 14.14.2 die Variable einer erweiterten for Schleife muss für die Schleife lokal sein. Mit anderen Worten, dies lässt sich kompilieren:

for (State state : State.values()) {
    // do something for each state
}

Dies ist jedoch nicht der Fall:

State state;
for (state: State.values()) {
    // do something for each state
}

In der JLS wird keine Begründung für diese Wahl des Sprachdesigns gegeben. Ich kann verstehen, warum der Typname vorhanden sein muss, wenn die lokale Variable durch final oder durch eine Anmerkung, aber ich verstehe nicht, warum der bloße Name einer an anderer Stelle deklarierten Variablen nicht zulässig ist. Kann mir jemand erklären, warum diese Einschränkung eingeführt wurde?

EDITAR

Mehrere Antworten scheinen darauf hinzudeuten, dass das, was außerhalb der Schleife geschieht, der Grund für die Gestaltung der Sprache auf diese Weise ist. Vielleicht wird eine genauere Betrachtung dessen, was die JLS sagt, klären, warum ich das nicht überzeugend finde. Betrachten Sie diese Schleife, in der State ist eine Aufzählung:

for (State state : State.values()) {
    // ...
}

State.values() ist ein Array, so dass die Schleife laut JLS funktional identisch ist mit:

State[] a = State.values();
for (int i = 0; i < a.length; i++) {
    State state = a[i];
    // ...
}

Diese letzte Schleife hätte natürlich auch geschrieben werden können:

State state;
State[] a = State.values();
for (int i = 0; i < a.length; i++) {
    state = a[i];
    // ...
}

Konzeptionell könnte diese letzte (völlig legale) Schleife als funktionales Äquivalent der zweiten erweiterten Schleife verwendet werden for Schleife (die sich nicht kompilieren lässt).

Ähnlich ist es, wenn stateList es un Iterable<State> (nicht ein Array), diese Schleife:

for (State state : stateList) {
    // ...
}

ist funktionell identisch mit:

for (Iterator<State> iterator = stateList.iterator(); iterator.hasNext(); ) {
    State state = iterator.next();
    // ...
}

Wie zuvor, diese letzte Schleife geschrieben werden können:

State state;
for (Iterator<State> iterator = stateList.iterator(); iterator.hasNext(); ) {
    state = iterator.next();
    // ...
}

Auch hier gilt könnte wurden als funktionales Äquivalent zu den (illegalen) verwendet:

State state;
for (state : stateList) {
    // ...
}

In jedem Fall wird beim Verlassen der Schleife der Wert von state ist vollkommen klar definiert (wenn auch vielleicht nutzlos). Genau wie bei der regulären Schleife kann auch eine erweiterte for Schleife mit einem bloßen Variablennamen, der nicht definiert wurde (z. B. die Zeile State state; fehlte oder außerhalb des Geltungsbereichs lag) könnte zur Kompilierzeit abgefangen werden. Wo liegt also aus Sicht des Sprachdesigns das Problem? Warum haben die Sprachentwickler dieses Konstrukt verboten?

11voto

Adithya Surampudi Punkte 4234

Sehen Sie sich an, wie die for-each-Schleife intern funktioniert, siehe Wie funktioniert die Java-'for each'-Schleife?

for(Iterator<String> i = someList.iterator(); i.hasNext(); ) {
String item = i.next();
System.out.println(item);
}

Jedes Mal, wenn sie die String-Variable item deklariert. Daher in Ihrem Fall seine tun im Wesentlichen

State state;
\\and inside
State state = i.next();

was natürlich nicht funktionieren wird. Jetzt innerhalb der Implementierung, sie könnte es eher nur tun

item = i.next();

aber dann müssen Sie dieses Element immer außerhalb von for-each definieren, was in den meisten Fällen schmerzhaft wäre.

9voto

havexz Punkte 9470

Ein Vorteil/eine Begründung ist, dass lokale Variablen den Code nicht verschmutzen. Lassen Sie mich eine normale Schleife Beispiel (dies ist nur für Analogie nicht eine genaue, also keine Iterator Verwendung):

int i;
for(i=0;i<10;i++)
  do...something

int j;
for(j=0; i<10; j++)
  do...something

Wenn Sie genau hinschauen, werden Sie im obigen Code einen möglichen Fehler finden. i wurde fälschlicherweise in einer Schleife verwendet, die sich über j .

Bei erweiterten Schleifen sollte man also auf Nummer sicher gehen, indem man die Variablen lokal erstellt, um das obige Problem zu vermeiden.

7voto

Bill K Punkte 61074

Viele Entscheidungen in Java basieren eher auf dem Konzept, warum man x nicht entfernen sollte. Warum in aller Welt sollte man zulassen, dass der Code verwirrt wird, indem man den Bereich außerhalb der Schleife verschiebt? Wenn Sie danach wirklich Zugriff auf das letzte Element benötigen, gibt es sauberere Wege.

Ich nehme an, einige mögen so oder so argumentieren, dass Java Programmierer vor sich selbst schützt, ich sehe es eher so, dass Java mich vor Leuten schützt, die solche Dinge ausnutzen wollen.

Es ist nicht wirklich eine großartige Hobbysprache, sondern eine großartige Team-Entwicklungssprache, bei der es darum geht, es dem Nächsten so einfach wie möglich zu machen, Ihren Code zu verstehen.

Ich habe zum Beispiel in einem Kommentar oben gesehen, dass viele Leute an einem bestimmten Punkt mit einem Wert aus einer for-Schleife aussteigen. Wie klar ist das, wenn man den Code durchsucht, um einen Fehler zu finden? Es sind die Leute, die solche raffinierten Tricks anwenden, vor denen ich wirklich geschützt werden möchte, nicht vor mir selbst.

Wenn Sie einen Code mitten in der Schleife ausführen möchten, fügen Sie ihn in eine Methode ein und rufen sie innerhalb der Schleife auf.

Das Fehlen von netten Tricks zwingt mich oft dazu, meinen Code zu überdenken und ein wenig härter zu arbeiten - aber die Ergebnisse sind immer lesbarer und wartbarer.

Wenn Sie nur ein einzelner Programmierer sind (nicht in einem Team), würde ich von Java abraten. Es macht keine netten Tricks und Sie werden keine coolen jährlichen Feature-Updates sehen - und es ist ziemlich langsam zu programmieren (es verlagert viel Zeit, um Fehler zu finden und zu beheben, in die Zeit, die man mit dem Programmieren verbringt, und frustriert die Leute mit seinen strengen Regeln (einer der größten Vorteile der Sprache IMO)

Wenn Sie etwas Java-ähnliches wollen, versuchen Sie stattdessen Scala. Wenn Sie aufgrund einer Entscheidung im Klassenzimmer "gezwungen" sind, Scala zu lernen, sollten Sie versuchen, es aus der Sicht des "Teams" und mit der Einstellung zu lernen, dass Sie in Zukunft nicht gezwungen sein werden, es zu benutzen.

5voto

Vlad Punkte 17635

Vielleicht wollten sie einen möglichen semantischen Unterschied zwischen dem einfachen for und dem erweiterten for beseitigen.

Wenn Sie z.B. eine normale for-Schleife hätten:

int i;
for (i=0; i<4; i++)
    ;

Wenn Sie die Schleife normal ausführen lassen, erhalten Sie die folgende Meldung i==4 nach der Schleife, was für die Iterationsvariable nicht gilt.

Was wäre, wenn Sie es könnten:

int i;
for (i : myArray)
    ;

Ich nehme an, dass es vom Standpunkt der Implementierung am einfachsten wäre, wenn am Ende i gleich dem letzten Element im Array waren. Aber sollte es sich so verhalten oder sollte es einen ungültigen Wert geben, und wenn ja, was könnte das sein? Was passiert, wenn man die letzte Iteration abbricht?

Eine andere Möglichkeit besteht darin, dass dadurch deutlicher wird, worum es in der Schleife geht und was der Elementtyp der Sammlung ist. Im Gegensatz dazu ist das einfache for in gewissem Sinne ein "altes" Konstrukt, so dass sie keine ähnliche Logik hätten anwenden können, ohne es zu "brechen" oder seine Flexibilität einzuschränken.

Ich spekuliere natürlich, und es könnte sich herausstellen, dass es nur eine zufällige Designentscheidung war.

3voto

Eng.Fouad Punkte 110730

Vielleicht, weil auf diese Weise gewährleistet wird, dass state ist leer und hat keinen Anfangswert zugewiesen bekommen.

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