60 votes

Comment "final int i" fonctionne-t-il dans une boucle Java for?

J'ai été surpris de voir que l'extrait de code Java suivant a été compilé et exécuté:

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

où listOfNumbers est un tableau d'entiers.

Je pensais que les déclarations finales avaient été assignées une seule fois. Le compilateur crée-t-il un objet Integer et modifie-t-il ses références?

66voto

Travis Gockel Points 11043

Imaginez que le raccourci ressemble beaucoup à ceci:

 for (Iterator<Integer> iter = listOfNumbers.iterator(); iter.hasNext(); )
{
    final int i = iter.next();
    {
        System.out.println(i);
    }
}
 

14voto

Recurse Points 2019

Voir @TravisG pour une explication des règles de portée impliqués. La seule raison pourquoi vous devez utiliser un final variable de boucle, comme c'est si vous avez besoin de se refermer sur elle dans un anonyme intérieur de la classe.

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 n'est pas dans le champ d'application de l'Exécutable, lorsqu'elle est exécutée, uniquement lorsqu'il est instancié. Sans l' final mot-clé de la variable de boucle ne serait pas visible à l'Exécutable, quand il finit par s'exécuter. Même s'il l'était, ce serait la même valeur pour tous les Runnables.

Btw, sur 10 ans, vous pourriez avoir vu une très faible amélioration de la vitesse de l'aide de final sur une variable locale (dans quelques rares occasions); qui n'a pas été le cas pendant longtemps. Maintenant, la seule raison de l'utilisation finale est à vous autoriser à utiliser une fermeture lexicale de ce genre.

En réponse à @mafutrct:

Lorsque vous écrivez du code, vous le faites pour les deux publics. La première est l'ordinateur qui, tant qu'il est syntaxiquement correct, va être heureux avec ce choix que vous faites. La deuxième est pour un futur lecteur (souvent même), ici le but est de communiquer le "intention" du code, sans occulter la "fonction" du code. Fonctionnalités de la langue doit être utilisée idiomatique avec quelques interprétations que possible afin de réduire les ambiguïtés.

Dans le cas de la variable de boucle, l'utilisation de final peut être utilisé pour communiquer, soit de deux choses l'une: seule la cession; ou, à la fermeture. Une simple analyse de la boucle est vous dire si la variable de boucle est réaffecté; toutefois, en raison de l'imbrication des deux chemins d'exécution lors de la création d'une clôture, il peut être facile d'oublier que la fermeture destiné à la capture de la variable. À moins, bien sûr, vous ne jamais utiliser final pour indiquer l'intention de capturer, au point où il devient évident pour le lecteur qu'est ce qui se passe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: