2014-07-22 4 views
5

Angesichts dieser Situation, wo ein Lambda innerhalb einer for-Schleife ist, würde ich erwarten, dass der Zähler i effektiv endgültig ist.Java Lambda - For-Schleife Zähler ist nicht effektiv endgültig

Der Compiler beklagt, dass ich nicht effektiv endgültig bin, also musste ich i2 verwenden. Die Frage ist, warum ich im Rahmen der for-Schleife nicht effektiv abschließend bin und dies die einfachste Problemumgehung ist.

+0

Wo benutzen Sie 'i' oder' i2'? – dkatzel

+0

effektiv endgültig? Ich bin mir nicht sicher, was das bedeutet. Ihr Code verwendet nicht einmal "i" in der Lambda –

+0

Entschuldigung für den Tippfehler - jetzt bearbeitet. – Dan

Antwort

0

Man muss bedenken, dass eine for Schleife tatsächlich äquivalent zu:

int i=0; 
while(i < x.getBooks().size()){ 
    //execute your block 
    i++; 
} 

Sie sehen also, dass i nur einmal deklariert und aktualisiert daher nicht effektiv endgültig.

Es ist ein wenig unklar, die Beziehung zwischen x.getBooks() und Book.getAuthors() aber anscheinend haben sie die gleiche Größe? Ohne ein besseres Verständnis, glaube ich nicht, dass ich Ihnen einen besseren Weg zeigen kann, dies zu tun. Aber das könnte Ihnen auch zeigen, dass Ihr Design schlecht ist.

+0

Das eigentliche Beispiel ist etwas hergestellt, so sorgen Sie sich nicht zu viel darüber. Die Hauptfrage betrifft den Umfang des Zählers in der for-Schleife. – Dan

+0

@Dan OK, dann reicht vielleicht der erste Teil meiner Antwort? – dkatzel

6

TLDR: i nicht final weil es modifiziert wird (i++) bei jeder Iteration der Schleife for.


why i is not effectively final inside the scope of the for loop ?

Die for Schleifensyntax ist

for (initialization; termination; increment) { 
    statement(s) 
} 

Die Inkrementausdruck nach jeder Iteration durch die Schleife aufgerufen wird. In Ihrem Fall ist das Inkrement i++, so dass i nach jeder Iteration geändert wird.

Sie können dies bestätigen i Letztendliche-Erklärung:

for (final int i = 0; i < x.getBooks().size(); i++) { 
} 

Sie diese Zusammenstellung Fehler:

The final local variable i cannot be assigned. 
It must be blank and not using a compound assignment 

is this the simplest workaround ?

Im Falle einer for Schleife: ja.

Aber Sie könnten eine while Schleife verwenden, wie sie durch @dkatzel oder ein foreach gezeigt:

int i = 0; 
for (Book book: x.getBooks()) { 
    int i2 = i; 
    ... 
    i++; 
} 
+1

In Ihrem 'foreach' Beispiel wurde die Semantik von' i' geändert. Es war 0 das erste Mal in der Schleife. Es wird jetzt das erste Mal sein. Auch das gleiche Problem, dass es nicht effektiv final ist, existiert, so dass 'i2' immer noch benötigt wird. –

+0

@ DavidConrad Sie haben Recht. Fest – gontard

5

Wie die anderen Antworten erwähnt, effectively final bedeutet, dass eine Variable kann nur einmal vergeben werden und neu zugewiesen nicht werden. Das ist in einer For-Schleife nicht der Fall. effectively final existiert, weil Entwickler sonst eine Variable explizit als final markieren müssen, um sie in einem Lambda zu verwenden.

jedoch der Grund, warum ich zu beantworten habe, ist eine Lösung, um Ihren Code zu schreiben, ohne i zu Duplizieren:

IntStream.range (0, x.getBooks().size()).forEach (i -> { 
    List<Book> books = bookstore.stream() 
           .filter(c -> c.getAuthors().get(i).equals("xxx")) 
           .collect(Collectors.toList()); 
}); 
1

Vom Java Language Specification

The scope of a local variable declared in the ForInit part of a basic for statement (§14.14.1) includes all of the following:

  • Its own initializer
  • Any further declarators to the right in the ForInit part of the for statement
  • The Expression and ForUpdate parts of the for statement
  • The contained Statement

Und über effectively final

A local variable or a method, constructor, lambda, or exception parameter is effectively final if it is not declared final but it never occurs as the left hand operand of an assignment operator (§15.26) or as the operand of a prefix or postfix increment or decrement operator

Ihre i Variable tritt als Operand Postfix Inkrementoperator

i++ 

Es ist daher nicht effektiv endgültig und nicht durch das Lambda eingefangen werden kann.