Pregunta ¿Cómo funciona el bucle Java 'for each'?


Considerar:

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

¿Cuál sería el equivalente for lazo parece sin usar el para cada ¿sintaxis?


1200
2017-09-17 16:44


origen


Respuestas:


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

Tenga en cuenta que si necesita usar i.remove(); en su bucle, o acceder al iterador real de alguna manera, no puede usar el for ( : ) idioma, ya que el iterador real es meramente inferido.

Como señaló Denis Bueno, este código funciona para cualquier objeto que implemente el Iterable interfaz.

Además, si el lado derecho de la for (:) idioma es un array en lugar de un Iterable objeto, el código interno utiliza un contador de índice int y contrasta array.length en lugar. Ver el Especificación del lenguaje Java.


967
2017-09-17 16:46



El constructo para cada también es válido para matrices. p.ej.

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

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

que es esencialmente equivalente de

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

Entonces, resumen general:
[nsayer] La siguiente es la forma más larga de lo que está sucediendo:

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

Tenga en cuenta que si necesita usar   yo remuevo(); en tu bucle, o acceso   el iterador real de alguna manera,   no puede usar el modificador for (:), ya que   el verdadero iterador es meramente   inferido

[Denis Bueno]

Está implícito en la respuesta de nsayer, pero   vale la pena señalar que los OP de (..)   la sintaxis funcionará cuando "someList" sea   cualquier cosa que implemente   java.lang.Iterable - no tiene   ser una lista o una colección de   java.util. Incluso tus propios tipos,   por lo tanto, se puede usar con esto   sintaxis.


423
2017-09-17 17:06



Aquí hay una respuesta que no supone conocimiento de Iteradores de Java. Es menos preciso, pero es útil para la educación.

Durante la programación, a menudo escribimos código que se parece a lo siguiente:

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 sintaxis foreach permite que este patrón común se escriba de una forma más natural y menos ruidosa desde el punto de vista sintáctico.

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

Además, esta sintaxis es válida para objetos tales como Listas o Conjuntos que no son compatibles con la indexación de matrices, pero que implementan la interfaz Iterable de Java.


119
2017-10-31 16:35



los foreach lazo, agregado en Java 5 (también llamado "Enhanced for loop"), es equivalente a usar un java.util.Iterator- Es azúcar sintáctico para la misma cosa. Por lo tanto, al leer cada elemento, uno por uno y en orden, un foreach siempre se debe elegir sobre un iterador, ya que es más conveniente y conciso.

para cada

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

Iterador

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

Hay situaciones en las que debe usar un Iterator directamente. Por ejemplo, intentar eliminar un elemento mientras se usa un foreach puede (¿será?) dar como resultado un ConcurrentModificationException.

foreach vs. for: Diferencias básicas

La única diferencia práctica entre for y foreach es que, en el caso de objetos indexables, no tiene acceso al índice. Un ejemplo cuando el básico for loop es obligatorio:

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

Aunque puede crear manualmente una variable int de índice separada con foreach,

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

no es recomendable, ya que Alcance variable no es ideal, y lo básico for loop es simplemente el formato estándar y esperado para este caso de uso.

foreach vs. for: Actuación

Al acceder a colecciones, una foreach es significativamente más rápido que el básico for acceso a la matriz de bucle Sin embargo, al acceder a las matrices, al menos con matrices primitivas y matrices contenedoras, el acceso a través de índices es mucho más rápido.

Temporización de la diferencia entre el acceso del iterador y el índice para prim-int-arrays

Los índices son 23-40 por ciento más rápido que los iteradores al acceder int o Integer matrices. Aquí está el resultado de la clase de prueba en la parte inferior de esta publicación, que suma los números en una matriz primitiva-int de 100 elementos (A es iterador, B es índice):

[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)

También ejecuté esto por un Integer array, y los índices siguen siendo el claro ganador, pero solo entre un 18 y un 25 por ciento más rápido.

Para las colecciones, los iteradores son más rápidos que los índices

Para List de Integers, sin embargo, los iteradores son el claro ganador. Simplemente cambie el int-array en la clase de prueba para:

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});

Y realice los cambios necesarios en la función de prueba (int[] a List<Integer>, length a 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)

En una prueba son casi equivalentes, pero con colecciones, el iterador gana.

* Esta publicación se basa en dos respuestas que escribí en Stack Overflow:

Más información: ¿Cuál es más eficiente, un bucle for-each o un iterador?

La clase de prueba completa

Creé esta clase compare-the-time-it-takes-to-do-any-two-things después de leer esta pregunta en desbordamiento de pila:

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



El ciclo for-each en Java usa el mecanismo iterador subyacente. Por lo tanto, es idéntico al siguiente:

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

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

34
2017-09-17 16:46



En las características de Java 8 puedes usar esto:

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

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

Salida

First
Second
Third

21
2018-04-19 15:22



Está implícito en la respuesta de nsayer, pero vale la pena señalar que los OP para sintaxis (..) funcionarán cuando "someList" sea cualquier cosa que implementa java.lang.Iterable - no tiene que ser una lista o una colección de java.util. Incluso sus propios tipos, por lo tanto, se pueden utilizar con esta sintaxis.


19
2017-09-17 16:50



Una sintaxis de bucle foreach es:

for (type obj:array) {...}

Ejemplo:

String[] s = {"Java", "Coffe", "Is", "Cool"};
for (String str:s /*s is the array*/) {
    System.out.println(str);
}

Salida:

Java
Coffe
Is
Cool

ADVERTENCIA: puede acceder a los elementos de la matriz con el ciclo foreach, pero NO puede inicializarlos. Usa el original for lazo para eso.

ADVERTENCIA: debe hacer coincidir el tipo de matriz con el otro objeto.

for (double b:s) // Invalid-double is not String

Si desea editar elementos, use el original for lazo como este:

for (int i = 0; i < s.length-1 /*-1 because of the 0 index */; i++) {
    if (i==1) //1 because once again I say the 0 index
        s[i]="2 is cool";
    else
        s[i] = "hello";
}

Ahora si volcamos s a la consola, obtenemos:

hello
2 is cool
hello
hello

18
2017-11-07 05:35



El constructo de bucle Java "for-each" permitirá la iteración sobre dos tipos de objetos:

  • T[]  (matrices de cualquier tipo)
  • java.lang.Iterable<T>

los Iterable<T> la interfaz tiene solo un método: Iterator<T> iterator(). Esto funciona en objetos de tipo Collection<T> porque el Collection<T> la interfaz se extiende Iterable<T>.


17
2017-09-17 18:04



El concepto de un bucle foreach como se menciona en Wikipedia se destaca a continuación:

Sin embargo, a diferencia de otros constructos de bucle, los bucles foreach generalmente   mantener sin contador explícito: esencialmente dicen "haz esto para   todo en este conjunto ", en lugar de" hacerlo x veces ". Esto evita   potencial errores uno por uno y hace que el código sea más simple de leer.

Por lo tanto, el concepto de un bucle foreach describe que el bucle no utiliza ningún contador explícito, lo que significa que no hay necesidad de usar índices para recorrer en la lista, por lo que se ahorra al usuario un error "uno por uno". Para describir el concepto general de este error "off-by-one", tomemos un ejemplo de un bucle para recorrer en una lista usando índices.

// In this loop it is assumed that the list starts with index 0
for(int i=0; i<list.length; i++){

}

Pero supongamos que si la lista comienza con el índice 1, este ciclo arrojará una excepción, ya que no encontrará ningún elemento en el índice 0 y este error se denomina error de uno a uno. Entonces, para evitar este error "uno por uno", se usa el concepto de un ciclo foreach. Puede haber otras ventajas también, pero esto es lo que creo que es el concepto principal y la ventaja de usar un ciclo foreach.


13
2017-10-04 07:47



Como se define en JLS for-each loop puede tener dos formas:

  1. Si el tipo de expresión es un subtipo de Iterable entonces la traducción es como:

    List<String> someList = new ArrayList<String>();
    someList.add("Apple");
    someList.add("Ball");
    for (String item : someList) {
        System.out.println(item);
    }
    
    // IS TRANSLATED TO:
    
    for(Iterator<String> stringIterator = someList.iterator(); stringIterator.hasNext(); ) {
        String item = stringIterator.next();
        System.out.println(item);
    }
    
  2. Si la expresión necesariamente tiene un tipo de matriz T[] entonces:

    String[] someArray = new String[2];
    someArray[0] = "Apple";
    someArray[1] = "Ball";
    
    for(String item2 : someArray) {
        System.out.println(item2);
    }
    
    // IS TRANSLATED TO:
    for (int i = 0; i < someArray.length; i++) {
        String item2 = someArray[i];
        System.out.println(item2);
    }
    

Java 8 ha introducido transmisiones que funcionan generalmente mejor. Podemos usarlos como:

someList.stream().forEach(System.out::println);
Arrays.stream(someArray).forEach(System.out::println);

12
2017-10-20 09:12