web-dev-qa-db-fra.com

Le journal des variables locales défini dans une portée englobante doit être final ou effectivement final

Je suis nouveau sur lambda et Java8. Je suis confronté à l'erreur suivante. 

Le journal des variables locales défini dans une étendue englobante doit être final ou effectivement final

public JavaRDD<String> modify(JavaRDD<String> filteredRdd) {

    filteredRdd.map(log -> {

        placeHolder.forEach(text -> {

            //error comes here
            log = log.replace(text, ",");

        });

        return log;

    });

    return null;
}
7
Balaji Reddy

Le message indique exactement le problème: votre journal de variable doit être final (c'est-à-dire: porter le mot-clé final) ou effectivement final (c'est-à-dire que vous ne lui attribuez une valeur qu'une fois en dehors du lambda). 

Sinon, vous ne pouvez pas utiliser cette variable dans votre instruction lambda. Mais bien sûr, cela est en conflit avec votre utilisation du journal. Le fait est que vous ne pouvez pas écrire sur quelque chose d'extérieur à l'intérieur de la lambda ... vous devez donc prendre du recul et rechercher d'autres moyens pour tout ce que vous avez l'intention de faire.

En ce sens: il suffit de croire le compilateur. 

12
GhostCat

La raison de cette limitation est identique à la raison de la fonctionnalité de langage Java selon laquelle variables locales accessible depuis les classes internes (anonymes) doit être (effectivement) final

Cette réponse de rgettman entre dans les détails. rgettman explique les limitations en détail et je fais un lien vers cette réponse car le comportement des expressions lambda devrait être identique à celui des classes internes anonymes. Notez qu’une telle limitation n’existe pas pour les variables de classe ou d’instance. La raison principale en est un peu compliquée et je ne pourrais pas l'expliquer mieux que ce que Roedy Green fait ici . Copier ici seulement pour qu'il soit à un endroit:

La règle est anonyme. Les classes internes ne peuvent accéder qu'au fichier final local variables de la méthode englobante. Pourquoi? Parce que la classe intérieure est les méthodes peuvent être invoquées plus tard, longtemps après la méthode qui les a engendrées a pris fin, par exemple par un événement AWT (Advanced Windowing Toolkit). Le les variables locales ont disparu depuis longtemps. La classe anonyme doit alors travailler avec des copies surgelées de ceux dont il a besoin cachés de manière cachée par le compilateur dans l'objet de classe interne anonyme. Vous pourriez demander, pourquoi les variables locales doivent-elles être définitives? Impossible pour le compilateur prenez tout aussi bien une copie des variables locales non finales, à peu près comme cela fait pour des paramètres non finaux? Si c'était le cas, vous auriez deux copies de la variable. Chacun pourrait changer indépendamment, un peu comme la copie d’un paramètre par l’appelant et l’appelé, mais vous utiliseriez le paramètre même syntaxe pour accéder à l'une ou l'autre copie. Ce serait déroutant. Alors Sun insisté pour que la section locale soit définitive. Cela rend inutile qu'il y ait en fait deux copies.

Possibilité pour une classe anonyme d’accéder au local local final de l’appelant variables est vraiment juste du sucre syntaxique pour passer automatiquement certaines variables locales en tant que paramètres de constructeur supplémentaires. Le tout me sent l’eau de kludge diluée.

10
Kedar Mhaswade

N'oubliez pas que les classes internes à la méthode ne peuvent modifier aucune valeur de la méthode qui les entoure. Votre deuxième expression lambda dans previsure tente d’accéder à sa variable de méthode environnante (log). 

Pour résoudre ce problème, vous pouvez éviter d'utiliser lambda in pour chaque option, donc un simple pour chacun et de rétablir toutes les valeurs du journal.

        filteredRdd.map(log -> {
        for (String text:placeHolder){
            log = log.replace(text,",");
        }
        return log;
    });
2
Mr.Q