Question Comment fonctionne la boucle Java «pour chaque»?


Considérer:

List<String> someList = new ArrayList<String>();
// add "monkey", "donkey", "skeleton key" to someList
for (String item : someList) {
    System.out.println(item);
}

Quel serait l'équivalent for boucle ressemble sans utiliser le pour chaque syntaxe?


1200
2017-09-17 16:44


origine


Réponses:


for (Iterator<String> i = someIterable.iterator(); i.hasNext();) {
    String item = i.next();
    System.out.println(item);
}

Notez que si vous devez utiliser i.remove(); dans votre boucle, ou accéder à l'itérateur réel d'une certaine façon, vous ne pouvez pas utiliser le for ( : ) idiome, puisque l'itérateur réel est simplement déduit.

Comme l'a noté Denis Bueno, ce code fonctionne pour tout objet qui implémente le Iterable interface.

En outre, si le côté droit de la for (:) idiome est un array plutôt qu'un Iterable objet, le code interne utilise un compteur d'index int et vérifie contre array.length au lieu. Voir le Spécification du langage Java.


967
2017-09-17 16:46



La construction pour chaque est également valable pour les tableaux. par exemple.

String[] fruits = new String[] { "Orange", "Apple", "Pear", "Strawberry" };

for (String fruit : fruits) {
    // fruit is an element of the `fruits` array.
}

qui est essentiellement équivalent de

for (int i = 0; i < fruits.length; i++) {
    String fruit = fruits[i];
    // fruit is an element of the `fruits` array.
}

Donc, résumé global:
[nsayer] Ce qui suit est la forme la plus longue de ce qui se passe:

for(Iterator<String> i = someList.iterator(); i.hasNext(); ) {
  String item = i.next();
  System.out.println(item);
}

Notez que si vous devez utiliser   i.remove (); dans votre boucle, ou l'accès   l'itérateur réel d'une certaine manière, vous   ne peut pas utiliser l'idiome for (:), puisque   l'itérateur réel est simplement   inféré.

[Denis Bueno]

C'est impliqué par la réponse de nsayer, mais   il est intéressant de noter que le PO pour (..)   la syntaxe fonctionnera quand "someList" est   tout ce qui met en œuvre   java.lang.Iterable - il n'a pas   être une liste, ou une collection de   java.util. Même vos propres types,   par conséquent, peut être utilisé avec cette   syntaxe.


423
2017-09-17 17:06



Voici une réponse qui ne suppose pas la connaissance des Iterators Java. C'est moins précis, mais c'est utile pour l'éducation.

Lors de la programmation, nous écrivons souvent du code qui ressemble à ceci:

char[] grades = ....
for(int i = 0; i < grades.length; i++) {   // for i goes from 0 to grades.length
    System.out.print(grades[i]);           // Print grades[i]
}

La syntaxe foreach permet d'écrire ce modèle commun d'une manière plus naturelle et moins syntaxiquement bruyante.

for(char grade : grades) {   // foreach grade in grades
    System.out.print(grade); // print that grade
}

En outre, cette syntaxe est valide pour les objets tels que les listes ou les ensembles qui ne prennent pas en charge l'indexation de tableau, mais qui implémentent l'interface Java Iterable.


119
2017-10-31 16:35



le foreach boucle, ajouté dans Java 5 (également appelé "enhanced for loop"), équivaut à utiliser un java.util.Iterator- Son sucre syntaxique pour la même chose. Par conséquent, en lisant chaque élément, un par un et dans l'ordre, un foreach devrait toujours être choisi sur un itérateur, car il est plus pratique et concis.

pour chaque

for(int i : intList) {
   System.out.println("An element in the list: " + i);
}

Iterator

Iterator<Integer> intItr = intList.iterator();
while(intItr.hasNext()) {
   System.out.println("An element in the list: " + intItr.next());
}

Il y a des situations où vous devez utiliser un Iterator directement. Par exemple, tenter de supprimer un élément en utilisant un foreach peut (va?) aboutir à un ConcurrentModificationException.

foreach contre. for: Différences fondamentales

La seule différence pratique entre for et foreach est que, dans le cas d'objets indexables, vous n'avez pas accès à l'index. Un exemple quand le basique for boucle est nécessaire:

for(int i = 0; i < array.length; i++) {
   if(i < 5) {
      // Do something special
   }  else {
      // Do other stuff
   }
}

Bien que vous puissiez créer manuellement un index séparé int-variable avec foreach,

int idx = -1;
for(int i : intArray) {
   idx++;
   ...
}

ce n'est pas recommandé, puisque variable-scope n'est pas idéal, et la base for loop est simplement le format standard et attendu pour ce cas d'utilisation.

foreach contre. for: Performance

Lors de l'accès aux collections, un foreach est significativement plus rapide que le basique for l'accès au tableau de la boucle. Toutefois, lors de l'accès aux tableaux, au moins avec les primitives et les wrapper-arrays, l'accès via les index est considérablement plus rapide.

Synchronisation de la différence entre l'accès à l'itérateur et à l'index pour les tableaux int-primitifs

Les index sont 23-40 pour cent plus rapide que les itérateurs lors de l'accès int ou Integer tableaux. Voici la sortie de la classe de test au bas de ce post, qui résume les nombres dans un tableau primitive-int de 100 éléments (A est l'itérateur, B est l'index):

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 358,597,622 nanoseconds
Test B: 269,167,681 nanoseconds
B faster by 89,429,941 nanoseconds (24.438799231635727% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 377,461,823 nanoseconds
Test B: 278,694,271 nanoseconds
B faster by 98,767,552 nanoseconds (25.666236154695838% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 288,953,495 nanoseconds
Test B: 207,050,523 nanoseconds
B faster by 81,902,972 nanoseconds (27.844689860906513% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 375,373,765 nanoseconds
Test B: 283,813,875 nanoseconds
B faster by 91,559,890 nanoseconds (23.891659337194227% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 375,790,818 nanoseconds
Test B: 220,770,915 nanoseconds
B faster by 155,019,903 nanoseconds (40.75164734599769% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 326,373,762 nanoseconds
Test B: 202,555,566 nanoseconds
B faster by 123,818,196 nanoseconds (37.437545972215744% faster)

J'ai aussi couru cela pour un Integer tableau, et les index sont toujours le gagnant clair, mais seulement entre 18 et 25 pour cent plus vite.

Pour les collections, les itérateurs sont plus rapides que les index

Pour un List de IntegersCependant, les itérateurs sont clairement les gagnants. Changez simplement le tableau int dans la classe de test pour:

List<Integer> intList = Arrays.asList(new Integer[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100});

Et apporter les modifications nécessaires à la fonction de test (int[] à List<Integer>, length à size(), etc.):

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 3,429,929,976 nanoseconds
Test B: 5,262,782,488 nanoseconds
A faster by 1,832,852,512 nanoseconds (34.326681820485675% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,907,391,427 nanoseconds
Test B: 3,957,718,459 nanoseconds
A faster by 1,050,327,032 nanoseconds (26.038700083921256% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,566,004,688 nanoseconds
Test B: 4,221,746,521 nanoseconds
A faster by 1,655,741,833 nanoseconds (38.71935684115413% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,770,945,276 nanoseconds
Test B: 3,829,077,158 nanoseconds
A faster by 1,058,131,882 nanoseconds (27.134122749113843% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 3,467,474,055 nanoseconds
Test B: 5,183,149,104 nanoseconds
A faster by 1,715,675,049 nanoseconds (32.60101667104192% faster)

[C:\java_code\]java TimeIteratorVsIndexIntList 1000000
Test A: 3,439,983,933 nanoseconds
Test B: 3,509,530,312 nanoseconds
A faster by 69,546,379 nanoseconds (1.4816434912159906% faster)

[C:\java_code\]java TimeIteratorVsIndexIntList 1000000
Test A: 3,451,101,466 nanoseconds
Test B: 5,057,979,210 nanoseconds
A faster by 1,606,877,744 nanoseconds (31.269164666060377% faster)

Dans un test, ils sont presque équivalents, mais avec des collections, l'itérateur gagne.

* Ce post est basé sur deux réponses que j'ai écrites sur Stack Overflow:

Quelques informations supplémentaires: Quel est le plus efficace, une boucle for-each, ou un itérateur?

La classe de test complète

J'ai créé cette classe compare-le-temps-il-prend-à-tout-deux-choses après avoir lu cette question sur le dépassement de pile:

import  java.text.NumberFormat;
import  java.util.Locale;

/**
   &lt;P&gt;{@code java TimeIteratorVsIndexIntArray 1000000}&lt;/P&gt;

   @see  &lt;CODE&gt;&lt;A HREF=&quot;https://stackoverflow.com/questions/180158/how-do-i-time-a-methods-execution-in-java&quot;&gt;https://stackoverflow.com/questions/180158/how-do-i-time-a-methods-execution-in-java&lt;/A&gt;&lt;/CODE&gt;
 **/
public class TimeIteratorVsIndexIntArray {

    public static final NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);

    public static final void main(String[] tryCount_inParamIdx0) {
        int testCount;

        // Get try-count from a command-line parameter
        try {
           testCount = Integer.parseInt(tryCount_inParamIdx0[0]);
        }
        catch(ArrayIndexOutOfBoundsException | NumberFormatException x) {
           throw  new IllegalArgumentException("Missing or invalid command line parameter: The number of testCount for each test. " + x);
        }

        //Test proper...START
        int[] intArray = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100};

        long lStart = System.nanoTime();
        for(int i = 0; i < testCount; i++) {
           testIterator(intArray);
        }

        long lADuration = outputGetNanoDuration("A", lStart);

        lStart = System.nanoTime();
        for(int i = 0; i < testCount; i++) {
           testFor(intArray);
        }

        long lBDuration = outputGetNanoDuration("B", lStart);

        outputGetABTestNanoDifference(lADuration, lBDuration, "A", "B");
    }

    private static final void testIterator(int[] int_array) {
       int total = 0;
       for(int i = 0; i < int_array.length; i++) {
          total += int_array[i];
       }
    }

    private static final void testFor(int[] int_array) {
       int total = 0;
       for(int i : int_array) {
          total += i;
       }
    }
    //Test proper...END

    //Timer testing utilities...START
    public static final long outputGetNanoDuration(String s_testName, long l_nanoStart) {
        long lDuration = System.nanoTime() - l_nanoStart;
        System.out.println("Test " + s_testName + ": " + nf.format(lDuration) + " nanoseconds");
        return  lDuration;
    }

    public static final long outputGetABTestNanoDifference(long l_aDuration, long l_bDuration, String s_aTestName, String s_bTestName) {
        long lDiff = -1;
        double dPct = -1.0;
        String sFaster = null;
        if(l_aDuration > l_bDuration) {
            lDiff = l_aDuration - l_bDuration;
            dPct = 100.00 - (l_bDuration * 100.0 / l_aDuration + 0.5);
            sFaster = "B";
        }
        else {
            lDiff = l_bDuration - l_aDuration;
            dPct = 100.00 - (l_aDuration * 100.0 / l_bDuration + 0.5);
            sFaster = "A";
        }
        System.out.println(sFaster + " faster by " + nf.format(lDiff) + " nanoseconds (" + dPct + "% faster)");
        return  lDiff;
   }

   //Timer testing utilities...END

}

114
2018-03-01 12:47



La boucle for-each de Java utilise le mécanisme d'itération sous-jacent. Donc, c'est identique au suivant:

Iterator<String> iterator = someList.iterator();

while (iterator.hasNext()) {
  String item = iterator.next();
  System.out.println(item);
}

34
2017-09-17 16:46



Dans Java 8, vous pouvez utiliser ceci:

List<String> messages = Arrays.asList("First", "Second", "Third");

void forTest(){
    messages.forEach(System.out::println);
}

Sortie

First
Second
Third

21
2018-04-19 15:22



Il est impliqué par la réponse de nsayer, mais il vaut la peine de noter que les OP de la syntaxe (..) fonctionneront quand "someList" est n'importe quoi qui implémente java.lang.Iterable - il ne doit pas être une liste, ou une collection de java.util. Même vos propres types peuvent donc être utilisés avec cette syntaxe.


19
2017-09-17 16:50