La variable utilisée dans l'expression lambda doit être finale ou effectivement finale
Lorsque j'essaye de l'utiliser, calTz
cette erreur s'affiche.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
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;
}
calTz
partir du lambda.Réponses:
Une
final
variable signifie qu'elle ne peut être instanciée qu'une seule fois. en Java, vous ne pouvez pas utiliser de variables non finales dans lambda ainsi que dans les classes internes anonymes.Vous pouvez refactoriser votre code avec l'ancienne boucle for-each:
Même si je n'ai pas le sens de certains morceaux de ce code:
v.getTimeZoneId();
sans utiliser sa valeur de retourcalTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
vous ne modifiez pas le passé initialementcalTz
et vous ne l'utilisez pas dans cette méthodenull
, pourquoi ne pas définirvoid
comme type de retour?J'espère aussi que ces conseils vous aideront à vous améliorer.
la source
Bien que d'autres réponses prouvent l'exigence, elles n'expliquent pas pourquoi l'exigence existe.
Le JLS mentionne pourquoi au §15.27.2 :
Pour réduire le risque de bogues, ils ont décidé de s'assurer que les variables capturées ne sont jamais mutées.
la source
À partir d'un lambda, vous ne pouvez pas obtenir de référence à tout ce qui n'est pas définitif. Vous devez déclarer un wrapper final de l'extérieur de la lamda pour contenir votre variable.
J'ai ajouté le dernier objet «référence» comme emballage.
la source
reference.set(calTz);
ou la référence doit être créée en utilisantnew AtomicReference<>(calTz)
, sinon la TimeZone non nulle fournie en paramètre sera perdue.Java 8 a un nouveau concept appelé variable «Effectivement final». Cela signifie qu'une variable locale non finale dont la valeur ne change jamais après l'initialisation est appelée «effectivement finale».
Ce concept a été introduit car avant Java 8 , nous ne pouvions pas utiliser de variable locale non finale dans une classe anonyme . Si vous voulez avoir accès à une variable locale dans une classe anonyme , vous devez la rendre définitive.
Lorsque lambda a été introduit, cette restriction a été assouplie. D'où la nécessité de rendre la variable locale finale si elle n'est pas modifiée une fois qu'elle est initialisée en tant que lambda en soi n'est rien d'autre qu'une classe anonyme.
Java 8 s'est rendu compte de la douleur de déclarer la variable locale final à chaque fois qu'un développeur utilisait lambda, a introduit ce concept et a rendu inutile la création de variables locales définitives. Donc, si vous voyez que la règle pour les classes anonymes n'a pas changé, c'est juste que vous n'avez pas à écrire le
final
mot - clé à chaque fois lorsque vous utilisez lambdas.J'ai trouvé une bonne explication ici
la source
effectively final
n'est pas du code, c'est de la terminologie. Voir Quand le formatage de code doit-il être utilisé pour le texte non codé? sur Meta Stack Overflow .final
mot - clé" est un mot de code et il est correct de formater de cette façon, mais lorsque vous utilisez "final" de manière descriptive plutôt que comme code, c'est plutôt une terminologie).Dans votre exemple, vous pouvez remplacer le
forEach
par lamdba par une simplefor
boucle et modifier n'importe quelle variable librement. Ou, probablement, refactorisez votre code afin que vous n'ayez pas besoin de modifier les variables. Cependant, je vais vous expliquer par souci d'exhaustivité ce que signifie l'erreur et comment la contourner.Spécification du langage Java 8, §15.27.2 :
Fondamentalement, vous ne pouvez pas modifier une variable locale (
calTz
dans ce cas) à partir d'un lambda (ou d'une classe locale / anonyme). Pour y parvenir en Java, vous devez utiliser un objet mutable et le modifier (via une variable finale) à partir du lambda. Un exemple d'objet mutable ici serait un tableau d'un élément:la source
s'il n'est pas nécessaire de modifier la variable, une solution de contournement générale pour ce genre de problème consisterait à extraire la partie de code qui utilise lambda et utilise le mot-clé final sur le paramètre de méthode.
la source
Une variable utilisée dans l'expression lambda doit être un final ou effectivement final, mais vous pouvez attribuer une valeur à un dernier tableau d'élément.
la source