Il modo più veloce per iterare un array in Java: variabile di ciclo vs migliorata per l'istruzione [duplicato]

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

  •  06-07-2019
  •  | 
  •  

Domanda

    

Questa domanda ha già una risposta qui:

         

In Java, è più veloce iterare attraverso un array alla vecchia maniera,

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

O usando il modulo più conciso,

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

Per una ArrayList, la risposta è la stessa?

Naturalmente per la maggior parte del codice dell'applicazione, la risposta è che non fa alcuna differenza riconoscibile, quindi il modulo più conciso dovrebbe essere usato per la leggibilità. Tuttavia, il contesto che sto esaminando è il calcolo tecnico per impieghi gravosi, con operazioni che devono essere eseguite miliardi di volte, quindi anche una piccola differenza di velocità potrebbe finire per essere significativa.

È stato utile?

Soluzione

Se esegui il looping di un array, non dovrebbe importare: il potenziato per loop utilizza comunque gli accessi agli array.

Ad esempio, considera questo codice:

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

Quando decompilato con javap -c Test otteniamo (per il metodo 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

Ora modificalo per utilizzare un accesso esplicito alla matrice:

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

Questo si decompila in:

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

C'è un po 'più di codice di installazione nel ciclo avanzato per, ma sostanzialmente stanno facendo la stessa cosa. Non sono coinvolti iteratori. Inoltre, mi aspetto che ottengano JITted con un codice ancora più simile.

Suggerimento: se pensi davvero che potrebbe fare una differenza significativa (cosa che mai farebbe solo se il corpo del loop fosse assolutamente minuscolo), allora dovresti confrontarlo con la tua vera applicazione. Questa è l'unica situazione che conta.

Altri suggerimenti

Questo rientra esattamente nell'arena della micro-ottimizzazione . Non importa davvero. Stilisticamente preferisco sempre il secondo perché è più conciso, a meno che tu non abbia bisogno del contatore del loop per qualcos'altro. E questo è molto più importante di questo tipo di micro-ottimizzazione : leggibilità.

Detto questo, per una ArrayList non ci sarà molta differenza, ma una LinkedList sarà molto più efficiente con la seconda.

Misuralo. La risposta a tutte le domande relative alle prestazioni può dipendere dalla versione della VM, dal processore, dalla velocità della memoria, dalle cache ecc. Quindi devi misurarla per la tua piattaforma specifica.

Personalmente preferirei la seconda variante, perché l'intenzione è più chiara. Se le prestazioni diventano un problema, posso ottimizzarle in un secondo momento - se quel codice è davvero importante per le prestazioni dell'intera applicazione.

Per un LinkedList:

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

Prima è stata data risposta:

Is c'è una differenza di prestazioni tra un ciclo for e un ciclo for-each?

Su un array o su una raccolta RandomAccess puoi ottenere un leggero aumento della velocità facendo:

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

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

Ma non mi preoccuperei in generale. Ottimizzazioni come questa non faranno più dello 0,1% di differenza sul tuo codice. Prova a invocare java con -prof per vedere dove il tuo codice sta effettivamente trascorrendo il suo tempo.

Ancora più veloce è usare ParallelArray del framework fork-join (se si dispone di un set di dati abbastanza grande).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top