La variabile utilizzata nell'espressione lambda deve essere definitiva o effettivamente definitiva. Quando provo a utilizzare calTz, viene visualizzato questo errore.utilizzata nell'espressione lambda deve essere definitiva o efficace finale
risposta
Una variabile final
significa che può essere istanziata solo una volta. in Java non è possibile utilizzare variabili non finali in lambda e nelle classi interne anonime.
È possibile refactoring del codice con il vecchio per-ogni loop:
private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
try {
for(Component component : cal.getComponents().getComponents("VTIMEZONE")) {
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if(calTz==null) {
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
}
}
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return null;
}
Anche se non ottengo il senso di alcuni pezzi di questo codice:
- si chiama un
v.getTimeZoneId();
senza utilizzare il suo valore di ritorno - con l'assegnazione
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
non si modifica l'origine passatocalTz
e non si utilizza in questo metodo - Si restituisce sempre
null
, perché non si impostavoid
come tipo di reso?
Spero anche che questi suggerimenti ti aiutino a migliorare.
Da un lambda, non è possibile ottenere un riferimento a tutto ciò che non è definitivo. Devi dichiarare un wrapper finale al di fuori della lama per mantenere la tua variabile.
Ho aggiunto l'oggetto "di riferimento" finale come questo wrapper.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
final AtomicReference<TimeZone> reference = new AtomicReference<>();
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component->{
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if(reference.get()==null) {
reference.set(TimeZone.getTimeZone(v.getTimeZoneId().getValue()));
}
});
} catch (Exception e) {
//log.warn("Unable to determine ical timezone", e);
}
return reference.get();
}
Stavo pensando allo stesso approccio o simile - ma mi piacerebbe vedere alcuni consigli di esperti/feedback su questa risposta? – YoYo
Nel tuo esempio, è possibile sostituire il forEach
con Lamdba con un semplice for
ciclo e modificare qualsiasi variabile liberamente. O, probabilmente, refactoring il codice in modo che non è necessario modificare le variabili. Tuttavia, spiegherò per completezza cosa significa l'errore e come aggirare il problema.
Java 8 Language Specification, §15.27.2:
Qualsiasi variabile locale, parametro formale, o il parametro eccezioni utilizzato ma non dichiarata in un'espressione lambda deve o essere dichiarata definitiva o essere efficacemente finale (§4.12.4), o un si verifica un errore in fase di compilazione in cui viene tentato l'utilizzo.
Fondamentalmente non è possibile modificare una variabile locale (calTz
in questo caso) da una lambda (o una classe locale/anonima). Per ottenere ciò in Java, devi usare un oggetto mutabile e modificarlo (tramite una variabile finale) dal lambda. Un esempio di un oggetto mutabile qui sarebbe un array di un elemento:
private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
TimeZone[] result = { null };
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
...
result[0] = ...;
...
}
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return result[0];
}
Java 8 ha un nuovo concetto chiamato variabile "Efficacemente finale". Significa che una variabile locale non finale il cui valore non cambia mai dopo l'inizializzazione è chiamata "Effettivamente finale". Questo concetto è stato introdotto perché prima di Java 8 non era possibile utilizzare una variabile locale non finale in una classe anonima. Se hai accesso a una variabile locale nella classe Anonymous, devi renderla definitiva. Quando Lambdas è stato introdotto, questa restrizione è stata attenuata. Quindi alla necessità di rendere locale varibale finale se non viene modificato una volta che è inizializzato come Lambda in sé non è altro che una classe anonima.Java 8 ha realizzato il dolore di dichiarare la variabile locale finale ogni volta che lo sviluppatore ha utilizzato Lambda e ha introdotto questo concetto e ha reso superfluo rendere definitive le variabili locali. Quindi, se vedi che la regola per la classe anonima non è ancora cambiata, è solo che non devi scrivere la parola chiave finale ogni volta che usi lambdas.
ho trovato una buona spiegazione here
se non è necessario modificare la variabile di una soluzione per questo tipo di problema sarebbe quello di estrarre la parte di codice che utilizzano lambda e utilizzare parola chiave final sul parametro-metodo.
- 1. L'accesso locale variabile alla classe interna deve essere dichiarato finale
- 2. Una variabile finale passata in Java rimane definitiva sull'altro lato?
- 3. Quando deve essere utilizzata l'annotazione di sicurezza 'denyAll'?
- 4. Come può ASLR essere efficace?
- 5. Java: utilizzo di una costante in una classe astratta che deve essere utilizzata anche da sottoclassi
- 6. Perché la classe di entità in JPA non può essere definitiva?
- 7. riferimento al campo finale da un'espressione lambda
- 8. RNMK - Super espressione deve essere o nullo o una funzione
- 9. Perché la variabile utilizzata per contenere il valore restituito da getchar deve essere dichiarata come int?
- 10. definitiva CRC per C
- 11. Web deve essere installato
- 12. Quando la classe Expando deve essere utilizzata nelle app di Google App Engine?
- 13. Lo spazio vuoto finale in varchar deve essere considerato in confronto
- 14. Perché una variabile finale deve essere inizializzata prima che il costruttore sia completato?
- 15. Perché una variabile NSInteger deve essere trasmessa su long se utilizzata come argomento di formato?
- 16. L'http deve essere utilizzata per le pagine successive di accesso https?
- 17. Perché una funzione di attivazione non lineare deve essere utilizzata in una rete neurale di backpropagation?
- 18. Come specificare quale interfaccia di rete deve essere utilizzata dall'emulatore Android sul mio computer di sviluppo?
- 19. La funzione deve essere utilizzata con un prefisso quando un namespace predefinito non è specificato
- 20. In un'applicazione Common Lisp con esecuzione prolungata, quale strategia deve essere utilizzata per gestire i rifiuti?
- 21. Quale vista deve essere utilizzata per il nuovo materiale Navigazione inferiore del design?
- 22. Le espressioni lambda/delegate in C# "puro" o possono essere?
- 23. "Utilizzare" deve essere all'interno del namespace o all'esterno?
- 24. Il costruttore di copia deve essere privato o pubblico
- 25. Un NSString letterale è autoreleased o deve essere rilasciato?
- 26. gcm canonical id deve essere aggiornato o meno
- 27. errore python3: valore_iniziale deve essere str o Nessuno
- 28. DDD: "Paese" deve essere un oggetto valore o un'entità?
- 29. MVP Android: un'attività deve essere una visualizzazione o un relatore?
- 30. La Promessa deve essere rifiutata con Errore o stringa?
Non è possibile modificare 'calTz' dal lambda. –
Dai un'occhiata [questo eccellente post di Bruce Eckel] (http://bruceeckel.github.io/2015/10/17/are-java-8-lambdas-closures/) su come Java 8 Lambdas è diverso da (Python) Chiusure e perché è possibile passare solo ** valori ** anziché ** variabili **. –