web-dev-qa-db-fra.com

Comment fonctionne-t-il "Final Int I" à l'intérieur d'A Java pour la boucle?

J'ai été surpris de voir que le suivant Java Code Snippet a compilé et couru:

for(final int i : listOfNumbers) {
     System.out.println(i);
}

où Listofnumbers est une gamme d'entiers.

Je pensais que les déclarations finales ne sont attribuées qu'une seule fois. Le compilateur crée-t-il un objet entier et en changeant ce qu'il références?

60
Abe

Voir @Travisg pour une explication des règles de slimage impliquées. La seule raison pour laquelle vous utiliseriez une variable de boucle finale comme celle-ci est si vous aviez besoin de fermer dessus dans une classe intérieure anonyme.

import Java.util.Arrays;
import Java.util.List;

public class FinalLoop {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(new Integer[] { 0,1,2,3,4 });
        Runnable[] runs = new Runnable[list.size()];

        for (final int i : list) {
            runs[i] = new Runnable() {
                    public void run() {
                        System.out.printf("Printing number %d\n", i);
                    }
                };
        }

        for (Runnable run : runs) {
            run.run();
        }
    }
}

La variable de boucle ne figure pas dans la portée du runnable lorsqu'il est exécuté, uniquement lorsqu'il est instancié. Sans le mot-clé final La variable de boucle ne serait pas visible par rapport à la runnable lorsqu'elle est finalement exécutée. Même si c'était le cas, ce serait la même valeur pour tous les runnables.

BTW, il y a environ 10 ans, vous avez peut-être constaté une très petite amélioration de la vitesse dans l'utilisation de la finale sur une variable locale (à quelques rares occasions); Cela n'a pas été le cas depuis longtemps. Maintenant, la seule raison d'utiliser finale est de vous permettre d'utiliser une fermeture lexicale comme celle-ci.

En réponse à @MAFUTRCT:

Lorsque vous écrivez le code, vous le faites pour deux audiences. Le premier est l'ordinateur qui, tant qu'il est syntaxiquement correct, sera satisfait des choix que vous faites. La seconde est pour un futur lecteur (souvent vous-même), le but est de communiquer l'intention du code, sans obscurcir la "fonction" du code. Les caractéristiques linguistiques doivent être utilisées sur le plan idiomatique avec aussi peu d'interprétations que possible pour réduire l'ambiguïté.

Dans le cas de la variable de boucle, l'utilisation de la finale pourrait être utilisée pour communiquer l'une des deux choses: une affectation unique; ou la fermeture. Une analyse triviale de la boucle vous indiquera si la variable de boucle est réaffectée; Cependant, en raison de l'entrelacement de deux chemins d'exécution lors de la création d'une fermeture, il peut être facile de manquer que la fermeture destinée à capturer la variable. À moins que, bien sûr, vous n'utilisez jamais final pour indiquer l'intention à capture, à laquelle cela devient évident pour le lecteur qui se passe.

14
Recurse