La forma más rápida de iterar una matriz en Java: variable de bucle versus mejorada para la instrucción [duplicado]

StackOverflow https://stackoverflow.com/questions/1006395

  •  06-07-2019
  •  | 
  •  

Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

En Java, ¿es más rápido iterar a través de una matriz a la antigua?

for (int i = 0; i < a.length; i++)
    f(a[i]);

O usando la forma más concisa,

for (Foo foo : a)
    f(foo);

Para una ArrayList, ¿la respuesta es la misma?

Por supuesto, para la gran mayoría del código de la aplicación, la respuesta es que no hace una diferencia apreciable, por lo que la forma más concisa se debe usar para facilitar la lectura. Sin embargo, el contexto que estoy viendo es el cálculo técnico pesado, con operaciones que deben realizarse miles de millones de veces, por lo que incluso una pequeña diferencia de velocidad podría terminar siendo significativa.

¿Fue útil?

Solución

Si está recorriendo una matriz, no debería importar: el bucle mejorado para utiliza accesos de matriz de todos modos.

Por ejemplo, considere este código:

public static void main(String[] args)
{
    for (String x : args)
    {
        System.out.println(x);
    }
}

Cuando se descompila con javap -c Test obtenemos (para el método main ):

public static void main(java.lang.String[]);
  Code:
   0:   aload_0
   1:   astore_1
   2:   aload_1
   3:   arraylength
   4:   istore_2
   5:   iconst_0
   6:   istore_3
   7:   iload_3
   8:   iload_2
   9:   if_icmpge   31
   12:  aload_1
   13:  iload_3
   14:  aaload
   15:  astore  4
   17:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  aload   4
   22:  invokevirtual   #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   25:  iinc    3, 1
   28:  goto    7
   31:  return

Ahora cámbielo para usar un acceso explícito a la matriz:

public static void main(String[] args)
{
    for (int i = 0; i < args.length; i++)
    {
        System.out.println(args[i]);
    }
}

Esto se descompila en:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   aload_0
   4:   arraylength
   5:   if_icmpge   23
   8:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  aload_0
   12:  iload_1
   13:  aaload
   14:  invokevirtual   #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   17:  iinc    1, 1
   20:  goto    2
   23:  return

Hay un poco más de código de configuración en el bucle for mejorado, pero básicamente están haciendo lo mismo. No hay iteradores involucrados. Además, esperaría que se JITted a un código aún más similar.

Sugerencia: si realmente cree que podría hacer una diferencia significativa (lo que alguna vez haría si el cuerpo del bucle es absolutamente minúsculo), debe compararlo con su aplicación real. Esa es la única situación que importa.

Otros consejos

Esto cae directamente en la arena de micro-optimización . Realmente no importa. Estilísticamente siempre prefiero el segundo porque es más conciso, a menos que necesite el contador de bucle para otra cosa. Y eso es mucho más importante que este tipo de microoptimización : legibilidad.

Dicho esto, para una ArrayList no habrá mucha diferencia, pero una LinkedList será mucho más eficiente con la segunda.

Mídelo. La respuesta a todas las preguntas de rendimiento puede depender de la versión de VM, el procesador, la velocidad de la memoria, los cachés, etc. Por lo tanto, debe medirla para su plataforma en particular.

Personalmente, preferiría la segunda variante, porque la intención es más clara. Si el rendimiento se convierte en un problema, puedo optimizarlo más adelante de todos modos, si ese código es realmente importante para el rendimiento de toda la aplicación.

Para una LinkedList:

for(ClassOfElement element : listOfElements) {
  System.out.println(element.getValue());
}

Se respondió antes:

es ¿Existe una diferencia de rendimiento entre un bucle for y un bucle for-each?

En una matriz o colección RandomAccess puede obtener un pequeño aumento en la velocidad haciendo:

List<Object> list = new ArrayList<Object>();

for (int i=0, d=list.size(); i<d; i++) {
    something(list.get(i));
}

Pero no me preocuparía en general. Optimizaciones como esta no harán más de 0.1% de diferencia en su código. Intente invocar Java con -prof para ver dónde su código realmente está gastando su tiempo.

Incluso más rápido es usar la matriz paralela del marco de la bifurcación (si tiene un conjunto de datos lo suficientemente grande).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top