2012-09-29 46 views
8

¿Cuál es la mejor forma de recorrer una matriz cuando necesita el índice?Práctica recomendada de Java for-loop

Opción 1:

int len = array.length; 
for (int i = 0; i < len; ++i) { 
    array[i] = foo(i); 
} 

Opción 2:

for (int i = 0; i < array.length; i++) { 
    array[i] = foo(i); 
} 

O, ¿no importa? ¿O hay una mejor manera de hacerlo? Solo para señalar las diferencias: en un caso, la longitud de la matriz se evalúa como parte de la prueba en el ciclo, aunque el compilador normalmente debería optimizar eso.


En segundo lugar, es ++i cualquiera diferente aquí desde i++? Definitivamente prefiero ++i si es C++, pero no estoy seguro de Java.

+3

Estos no debería haber ningún diferente. –

Respuesta

6

i++ versus ++i no importa en este caso particular. Mientras que los maestros de C le indicarán que almacene array.length en una variable, los compiladores de optimización modernos lo hacen innecesario en este caso siempre que la longitud no cambie en el ciclo. Si está realmente preocupado, puede comparar ambos, pero dado que .length en realidad no necesita recorrer toda la matriz cada vez, estará bien.

+0

¡Gran respuesta! En realidad, también se recomienda utilizar siempre la opción 1, ¿no? –

+0

Opción 1 a cuál pregunta? Para 'i ++' vs '++ i'? Prefiero 'i ++' por motivos de legibilidad, pero puedo ver por qué '++ i' podría ser un mejor valor predeterminado, por lo que el nuevo valor de' i' se usa en caso de que cambies tu código y no notes el postincremento. '++ i' también es más rápido para los compiladores estúpidos que no se dan cuenta de que al usuario no le importa qué valor tiene la expresión. – Dan

+0

No, me refiero a la opción 1 para '.length'. Para '++ i' contra' i ++ ', creo que es solo un problema de estilo de código. –

6

En general, esos dos métodos son equivalentes. Debe tener en cuenta que, en

for (int i = 0 ; i < foo() ; i++) { 
    ... 
} 

la foo() se llama una vez antes de cada iteración (a diferencia de una sola vez antes de la primera iteración), por lo que es posible que desee tener esto en cuenta para situaciones más complicadas por tal vez haciendo algo como

int n = foo(); 
for (int i = 0 ; i < n ; i++) { 
    ... 
} 

que es análoga a la Opción 1 . Así que yo diría que Opción 1 es sin duda la más segura de las dos, pero la mayoría de las veces no debería hacer una diferencia significativa que usted use.


En cuanto a su segunda pregunta: ++i primeros incrementos de la variable y luego recupera su valor, i++ primera recupera el valor y luego incrementos. Solo trata de estas dos piezas de código:

int i = 0; 
System.out.println(++i); 
------------------------ 
int i = 0; 
System.out.println(i++); 

Las primeras impresiones 1 pero la segunda imprime 0. Por supuesto, cuando ++i y i++ están solos, no hace la diferencia.

+0

No veo 'i

+0

@BheshGurung Esa función 'foo' demuestra cómo se evalúan repetidamente las rhs de las condiciones for-loop, como mencioné. Cuando tienes algo como 'array.length' en el rhs, no hará ninguna diferencia. Pero cuando tienes algo como 'foo', debes tener cuidado hasta cierto punto. – arshajii

+0

@arshajii Me preocupaba que foo() en el caso del acceso a size() ralentizara las cosas y realicé algunas pruebas (ver última respuesta). Aparentemente es lo mismo. ¿El compilador simplemente transforma el tamaño() en un simple acceso de var en tiempo de compilación? – Ced

0

de si se debe utilizar "Array.length" en bucle: Generalmente el compilador va a hacer alguna optimización, como resultado es equivalente a usar una variable en el bucle for

para "i ++" y " ++ i " En C++, se prefiere ++ y es más eficiente, pero en Java son equivalentes en este caso.

0

Además de la respuesta de arshaji, quería saber si había un beneficio en el rendimiento al usar size() en un ciclo versus almacenarlo por adelantado.Creo que el resultado muestra que el compilador optimiza las cosas y acceder a la longitud de una lista es lo mismo que acceder a una variable (me preocupaba que el hecho de tener que pasar por una función ralentizara las cosas).

Aquí es el tiempo que toma para los dos para diverso método de bucle:

for(long i = 0 ; i < mylist.size(); i++){} 
VS 
for(long i = 0 ; i < 10_000_000; i++){} 

Este es el resultado de una lista de diez millones de elems:

fixed length: 
,162,157,151,157,156,159,157,149,150,170,158,153,152,158,151,151,156,156,151,153 
getSize: 
,164,156,159,154,151,160,162,152,154,152,151,149,168,156,152,150,157,150,156,157 



import java.util.ArrayList; 
import java.util.List; 

public class Main { 

    final static int LENGTH_SAMPLE = 20; 
    final static long LENGTH = 10_000_000; 

    public static void main(String[] args) { 

     List<Long> mylist = new ArrayList<>(); 
     for(long i = 0 ; i < LENGTH; i++){ 
      mylist.add(i); 
     } 
     System.out.println("fixed length:"); 
     for(int i = 0 ; i < LENGTH_SAMPLE; i++){ 
      System.out.printf("," + fixedSize(mylist)); 
     } 
     System.out.println(""); 
     System.out.println("getSize:"); 
     for(int i = 0 ; i < LENGTH_SAMPLE; i++){ 
      System.out.printf("," + fctSize(mylist)); 
     } 
    } 

    private static long fixedSize(List list){ 
     long start = System.currentTimeMillis(); 

     for(long i = 0 ; i < LENGTH; i++){ 
      System.currentTimeMillis(); 
     } 
     return System.currentTimeMillis() - start; 
    } 

    private static long fctSize(List list){ 
     long start = System.currentTimeMillis(); 

     for(long i = 0 ; i < list.size(); i++){ 
      System.currentTimeMillis(); 
     } 
     return System.currentTimeMillis() - start; 
    } 
} 
Cuestiones relacionadas