Spiegami che in che modo l'espressione lambda può utilizzare e modificare la variabile di istanza della sua classe di inclusione e può utilizzare solo la variabile locale del suo ambito (a meno che non sia finale o finale effettivo)? La mia base domanda è come variabile della classe di istanza è modificabile all'interno di Lambda e variabile locale non è, in un contesto di portataEspressione lambda e cattura variabile
risposta
In un primo momento, siamo in grado di dare uno sguardo al JLS, in cui si afferma quanto segue:
Qualsiasi variabile locale, parametro formale o parametro di eccezione utilizzato ma non dichiarato in un'espressione lambda deve essere dichiarato finale o essere effettivamente definitivo (§4.12.4), oppure si verifica un errore in fase di compilazione in cui viene tentato l'utilizzo.
Qualsiasi variabile locale utilizzata ma non dichiarata in un corpo lambda deve essere assegnata definitivamente (§16 (Assegnazione definita)) prima del corpo lambda o si verifica un errore in fase di compilazione.
Regole simili sull'uso variabile si applicano nel corpo di una classe interna (§8.1.3). La restrizione alle variabili finali effettivamente proibisce l'accesso a variabili locali che cambiano dinamicamente, la cui cattura potrebbe introdurre problemi di concorrenza. Rispetto alla restrizione finale, riduce il carico di lavoro dei programmatori.
La restrizione alle variabili finali effettive include variabili di ciclo standard, ma non potenziate per le variabili di ciclo, che vengono considerate distinte per ciascuna iterazione del ciclo (§14.14.2).
per capire meglio, dare un'occhiata a questo esempio di classe:
public class LambdaTest {
public static void main(String[] args) {
LambdaTest test = new LambdaTest();
test.returnConsumer().accept("Hello");
test.returnConsumerWithInstanceVariable().accept("Hello");
test.returnConsumerWithLocalFinalVariable().accept("Hello");
}
String string = " world!";
Consumer<String> returnConsumer() {
return ((s) -> {System.out.println(s);});
}
Consumer<String> returnConsumerWithInstanceVariable() {
return ((s) -> {System.out.println(s + string);});
}
Consumer<String> returnConsumerWithLocalFinalVariable() {
final String foo = " you there!";
return ((s) -> {System.out.println(s + foo);});
}
}
uscita di principale è
Hello
Hello world!
Hello you there!
Questo perché la restituzione di un lambda qui è più o meno la come creare una nuova classe anonima con new Consumer<String>() {...}
. Il tuo lambda - un'istanza di Consumer<String>
ha un riferimento alla classe in cui è stato creato. Puoi riscrivere la variabile returnConsumerWithInstanceVariable per utilizzare System.out.println(s + LambdaTest.this.string)
, questo farebbe esattamente lo stesso. Questo è il motivo per cui è consentito accedere (e modificare) variabili di istanza.
Se nel metodo è presente una variabile locale finale (effettiva), è possibile accedervi poiché è possibile accedervi poiché viene copiata nell'istanza lambda.
Ma, tuttavia, se non definitivo, cosa pensi che dovrebbe accadere nel contesto seguente:
Consumer<String> returnConsumerBad() {
String foo = " you there!";
Consumer<String> results = ((s) -> {System.out.println(s + foo);});
foo = " to all of you!";
return results;
}
Qualora il valore vengono copiati per l'istanza, ma poi non si aggiorna quando la variabile locale è aggiornato? Ciò probabilmente causerebbe confusione, poiché penso che molti programmatori si aspettassero di avere il nuovo valore "per tutti voi" dopo aver restituito questo lambda.
Se si dispone di un valore primitivo, si posiziona in pila. Quindi non puoi semplicemente fare riferimento alla variabile locale, perché potrebbe scomparire dopo che è stata raggiunta la fine del tuo metodo.
È possibile consultare questo articolo - https://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood
spiegato sulla compilazione di espressioni lambda.Come spiegato le espressioni lambda/i blocchi di codice sono compilati nella classe anonima, queste classi anonime sono compilate con il formato del nome (<<Enclosing Class name>>$<<1(Number)>>
), quindi supponiamo di assumere se non sono consentite variabili locali non definitive, quindi il compilatore non può rintracciare da dove questa variabile locale è riferita come classe anonima i file .class vengono creati/compilati con il formato sopracitato separatamente come le normali classi java.
Quindi se la variabile locale è definitiva, il compilatore crea un'istanza finale nella classe anoymous che non crea ambiguità al compilatore. Per ulteriori informazioni, fare riferimento al collegamento menzionato
- 1. Espressione lambda che cattura di nascosto `this`
- 2. C++ lambda - variabile membro di cattura
- 3. regola per la variabile cattura lambda
- 4. C#: nessuna conversione implicita tra "espressione lambda" e "espressione lambda"?
- 5. C++ - espressione lambda, clausola di acquisizione e membri della classe
- 6. Lambda cattura di riferimento copiando e decltype
- 7. Thread con espressione Lambda
- 8. Espressione Lambda contro affermazione Lambda
- 9. Espressione lambda C++ in std :: find_if?
- 10. espressione lambda come proprietà
- 11. Sostituire parametro espressione lambda
- 12. C++ Lambda cattura membro della classe privata
- 13. Compilazione espressione lambda
- 14. Espressione lambda in PowerShell
- 15. . Espressione lambda netta e parametro out
- 16. Delegati, Azioni, Eventi, espressione Lambda e MVVM
- 17. Jersey e Java 8 (espressione Lambda)
- 18. Bloccato con espressione lambda e mappa
- 19. Null-coalescenza operatore e lambda espressione
- 20. Espressione lambda in Java?
- 21. C++ lambda cattura per valore
- 22. nidificati Lambda problema di cattura
- 23. chiamate all'interno espressione lambda
- 24. Lambda espressione per setter
- 25. Sintassi di espressione lambda
- 26. Espressione lambda in C#
- 27. Vincoli di cattura lambda C++
- 28. Passo lambda espressione all'argomento lambda C++ 11
- 29. valore Cattura di variabili sulla creazione lambda
- 30. C++ lambda valore copia nella cattura-list
Poiché lambda è effettivamente una classe interna anonima, questo è un possibile duplicato di [Perché solo le variabili finali sono accessibili nella classe anonima?] (Http://stackoverflow.com/questions/ 4732544/why-are-only-final-variables-accessible-in-anonimo-class) – mthmulders
Questo è vero per Java 8, ma per quanto ne so non è specificato, quindi questo potrebbe essere cambiato nelle versioni future di Java. – Alex
solo "questo" viene catturato. tutto l'accesso a una variabile di istanza all'interno del corpo lambda avviene tramite 'this.field', quindi puoi scrivere anche su di esso. – ZhongYu