Java 8 capture 22 avec des expressions lambda et effectivement finale
Je suis en train de jouer avec Java 8 et frappé d'un scénario de base qui illustre un catch 22 où corriger une erreur de compilation provoque une autre erreur de compilation. Le scénario (qui est juste un exemple simplifié de quelque chose de plus complexe):
public static List<String> catch22(List<String> input) {
List<String> result = null;
if (input != null) {
result = new ArrayList<>(input.size());
input.forEach(e -> result.add(e)); //compile error here
}
return result;
}
J'obtiens une erreur de compilation:
Variable locale suite définie dans un cadre englobant doit être définitive ou efficacement final
Si je change la première ligne:
List<String> result;
J'obtiens une erreur de compilation sur la dernière ligne:
La variable locale résultat peut ne pas avoir été initialisé
Il semble que la seule solution ici est de pré-initialiser mon résultat à une liste de tableaux, dont je ne veux pas faire, ou ne pas utiliser les expressions lambda. Ai-je raté une autre solution?
source d'informationauteur Josh Stone | 2014-04-01
Vous devez vous connecter pour publier un commentaire.
L'erreur est venue parce que votre
result
liste n'est pas effectivementfinal
qui est une des exigences pour l'utilisation de lambda. Une option est de déclarer la variable à l'intérieur de laif
condition, etreturn null;
à l'extérieur. Mais je ne pense pas que ce serait une bonne idée. Votre méthode actuelle est de ne rien faire de productif. Il serait beaucoup plus logique de renvoyer une liste vide.Après avoir dit que, je dirais, puisque vous jouez avec Java 8, utilisez
Facultatif
avec des ruisseaux ici:Et si vous souhaitez revenir
null
je vais probablement changer votre méthode:Pousser la déclaration à l'intérieur du bloc avec entrée != la valeur null. Exemple:
forEach(...)
s'applique à une opération sur chaque élément de laStream
. Vous ne voulez vraiment pas que, vous voulez unStream
"consommateurs" qui produit une sortie unique deList<String>
.Heureusement, ils sont considérés comme
Collector
s dans le cadre actuel, etCollectors.toList()
fait exactement ce que vous voulez.En rendant le résultat final et de mettre de l'null affectation dans le bloc else vous pouvez conserver la structure actuelle de votre méthode et de "résoudre" votre catch22.
Vous pouvez le faire
de les contourner.
Sa présence empêche l'introduction d'une nouvelle classe de multithreading bugs impliquant des variables locales.
Les variables locales en Java ont jusqu'à présent été à l'abri de conditions de course et la visibilité des problèmes parce qu'ils ne sont accessibles qu'au fil de l'exécution de la méthode dans laquelle elles sont déclarées. Mais un lambda peut être transmis dans le thread qui a créé il à un thread différent, et que l'immunité, par conséquent, être perdu si le lambda, évaluées par le second thread, ont eu la possibilité de muter des variables locales.
Même la possibilité de lire la valeur de la mutable variables locales à partir d'un autre thread introduire la nécessité pour la synchronisation ou l'utilisation de volatiles afin d'éviter de lire des données périmées.
Ici, j'ai fait un résumé de certaines des solutions générales pour les lambdas expressions de la modification de la méthode des variables locales.
Lambdas Expressions sont en fait les classes internes anonymes, sous une forme concise. Lorsque nous les utilisons dans les méthodes locales, nous devrions prendre plusieurs contraintes en considération:
lambdas expressions(anonyme intérieur de la classe) cant modifier les variables locales autour de la méthode lien ici ils doivent être définitive ou en java 8 effectivement final
Contrairement aux variables d'instance, les variables locales n'obtenez pas les valeurs par défaut et si vous souhaitez utiliser ou de retour, vous devez les initialiser première
Lorsque ces deux contraintes entrent en collision (dans le cas de la définition d'un lambdas dans une méthode où les lambdas modifie la variable locale à la périphérie de la méthode), nous avons des ennuis
solutions:
solution 1: ne pas modifier la méthode de la variable locale dans les lambdas ou de l'utilisation de variables d'instance, au lieu
solution 2: faire quelques trucs, par exemple la copie locale de la variable dans un autre, et passer à des lambdas:
ou de limiter la portée de variables de sorte que vous ne pas avoir des ennuis pour ne pas l'initialiser: