Java: il modo migliore per scorrere una raccolta (qui ArrayList)


98

Oggi stavo felicemente programmando quando sono arrivato a un pezzo di codice che ho già usato centinaia di volte:

Iterazione attraverso una raccolta (qui ArrayList)

Per qualche motivo, ho effettivamente esaminato le opzioni di completamento automatico di Eclipse e mi sono chiesto:

Quali sono i casi migliori da usare rispetto agli altri?

Il classico ciclo dell'indice dell'array:

for (int i = 0; i < collection.length; i++) {
  type array_element = collection.get(index);
}

L'iteratore haNext () / next ():

for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
  type type = (type) iterator.next();   
}

E il mio preferito perché è così semplice da scrivere:

for (iterable_type iterable_element : collection) {

}

2
Quando si tratta di me, utilizzo principalmente il 3 ° ciclo.
Harry Joy

1
Per il secondo modo è meglio usare:for (Iterator<type> iterator = collection.iterator(); iterator.hasNext();) { type type = iterator.next(); }
mike jones

4
L'interfaccia della raccolta non contiene un metodo "get", quindi il primo non è sempre possibile.
ThePerson

Risposte:


104

Il primo è utile quando è necessario anche l'indice dell'elemento. Questo è fondamentalmente equivalente alle altre due varianti di ArrayLists, ma sarà molto lento se usi un file LinkedList.

Il secondo è utile quando non è necessario l'indice dell'elemento ma potrebbe essere necessario rimuovere gli elementi durante l'iterazione. Ma questo ha lo svantaggio di essere un po 'troppo prolisso IMO.

Anche la terza versione è la mia scelta preferita. È breve e funziona per tutti i casi in cui non è necessario alcun indice o l'iteratore sottostante (ovvero si accede solo agli elementi, non li si rimuove o si modifica Collectionin alcun modo - che è il caso più comune).


3
+1 Battimi fino in fondo. stava per menzionare LinkedList (non tutte Collection sono economiche da recuperare tramite indice).
The Scrum Meister

Finché è necessario eseguire il loop degli elementi, è sempre bene usare la terza versione, poiché l'implementazione esiste già per tutte le diverse collezioni e Sun o qualsiasi implementazione JDK si sforza di migliorare le prestazioni piuttosto che tutte.
Phani

@Phani: le altre due varianti funzionano anche su qualsiasi implementazione JDK.
MAK

Non ho detto che quelli non funzionerebbero, ma se per caso venissero apportati alcuni miglioramenti o modifiche alle prestazioni per le implementazioni delle raccolte, allora si applicherebbe automaticamente al tuo codice e non avrai bisogno di scrivere per migliorare le prestazioni è quello che intendo.
Phani

1
@Phani: AFAIK la terza forma è semplicemente zucchero sintattico per la seconda forma (cioè sotto il cofano la variante foreach utilizza effettivamente un iteratore). Quindi qualsiasi vantaggio in termini di prestazioni dovrebbe essere disponibile per entrambe le varianti. La prima versione ovviamente non otterrebbe alcun vantaggio in termini di prestazioni (ad esempio, se Listfosse implementato come un albero, sarebbe effettivamente più lento).
MAK

36

Tutti hanno usi propri:

  1. Se hai un iterabile e devi attraversarli incondizionatamente verso tutti loro:

    per (iterable_type iterable_element: collection)

  2. Se hai un iterabile ma devi attraversare in modo condizionale:

    for (Iterator iterator = collection.iterator (); iterator.hasNext ();)

  3. Se la struttura dati non implementa iterabile:

    for (int i = 0; i <collection.length; i ++)


Puoi farlo per attraversare il primo metodo in modo condizionale: if (iterable_element.some_attribute) {// fa qualcosa; } altro {// non fare nulla; }. Se sì, sostanzialmente non c'è differenza tra il primo e il secondo metodo, a parte lo zucchero sintattico.
Thomas Nguyen,

1 è in grado di attraversare condizionatamente come gli altri usando breake / ocontinue
arcyqwerty

13

C'è anche l'utility stream () di collections con Java 8

collection.forEach((temp) -> {
            System.out.println(temp);
});

o

collection.forEach(System.out::println);

Ulteriori informazioni su Java 8 stream e raccolte per il collegamento Wonderers


4

Nessuno di loro è "migliore" degli altri. Il terzo è, per me, più leggibile, ma a qualcuno che non usa foreach potrebbe sembrare strano (potrebbero preferire il primo). Tutti e 3 sono abbastanza chiari per chiunque capisca Java, quindi scegli quello che ti fa sentire meglio con il codice.

Il primo è il più semplice, quindi è il modello più universale (funziona per gli array, tutti gli iterabili a cui riesco a pensare). Questa è l'unica differenza a cui riesco a pensare. In casi più complicati (es. Devi avere accesso all'indice corrente, o devi filtrare l'elenco), il primo e il secondo caso potrebbero avere più senso, rispettivamente. Per il caso semplice (oggetto iterabile, nessun requisito speciale), il terzo sembra il più pulito.


2

La prima opzione è migliore per quanto riguarda le prestazioni (poiché ArrayList implementa l'interfaccia RandomAccess). Secondo il documento java, un'implementazione di List dovrebbe implementare l'interfaccia RandomAccess se, per istanze tipiche della classe, questo ciclo:

 for (int i=0, n=list.size(); i < n; i++)
     list.get(i);

funziona più velocemente di questo ciclo:

 for (Iterator i=list.iterator(); i.hasNext(); )
     i.next();

Spero possa essere d'aiuto. La prima opzione sarebbe lenta per gli elenchi di accesso sequenziale.


1

Ecco un esempio

Query query = em.createQuery("from Student");
             java.util.List list = query.getResultList();
             for (int i = 0; i < list.size(); i++) 
             {

                 student = (Student) list.get(i);
                 System.out.println(student.id  + "  " + student.age + " " + student.name + " " + student.prenom);

             }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.