Java: Der beste Weg, um eine Sammlung zu durchlaufen (hier ArrayList)

98

Heute habe ich glücklich codiert, als ich zu einem Code kam, den ich bereits hunderte Male verwendet habe:

Durch eine Sammlung iterieren (hier ArrayList)

Aus irgendeinem Grund habe ich mir die Optionen für die automatische Vervollständigung von Eclipse angesehen und mich gefragt:

In welchen Fällen sind die folgenden Schleifen besser zu verwenden als die anderen?

Die klassische Array-Indexschleife:

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

Der Iterator hatNext () / next ():

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

Und mein Favorit, weil es so einfach zu schreiben ist:

for (iterable_type iterable_element : collection) {

}
Jason Rogers
quelle
2
Wenn es um mich geht, benutze ich meistens die 3. Schleife.
Harry Joy
1
Für den zweiten Weg ist es besser zu verwenden:for (Iterator<type> iterator = collection.iterator(); iterator.hasNext();) { type type = iterator.next(); }
Mike Jones
4
Die Erfassungsschnittstelle enthält keine Methode "get", daher ist die erste nicht immer möglich.
ThePerson

Antworten:

104

Der erste ist nützlich, wenn Sie auch den Index des Elements benötigen. Dies entspricht im Grunde den beiden anderen Varianten für ArrayLists, ist jedoch sehr langsam, wenn Sie a verwenden LinkedList.

Der zweite ist nützlich, wenn Sie den Index des Elements nicht benötigen, die Elemente jedoch möglicherweise während der Iteration entfernen müssen. Dies hat jedoch den Nachteil, dass die IMO etwas zu ausführlich ist.

Die dritte Version ist auch meine bevorzugte Wahl. Es ist kurz und funktioniert in allen Fällen, in denen Sie keine Indizes oder den zugrunde liegenden Iterator benötigen (dh Sie greifen nur auf Elemente zu, entfernen sie nicht oder ändern sie Collectionin irgendeiner Weise - was der häufigste Fall ist).

MAK
quelle
3
+1 Schlage mich dazu. wollte LinkedList erwähnen (nicht alle Collection sind billig per Index abzurufen).
Der Scrum Meister
Solange nur Elemente geloopt werden müssen, ist es immer gut, die 3. Version zu verwenden, da die Implementierung bereits für alle verschiedenen Collections and Sun vorhanden ist oder jede JDK-Implementierung versucht, die Leistung zu verbessern, anstatt jede einzelne.
Phani
@Phani: Die beiden anderen Varianten funktionieren auch bei jeder JDK-Implementierung.
MAK
Ich habe nicht gesagt, dass diese nicht funktionieren würden, aber wenn zufällig bestimmte Verbesserungen oder Leistungsänderungen für die Implementierung von Sammlungen vorgenommen werden, würde dies automatisch für Ihren Code gelten und Sie müssen nicht schreiben, um die Leistung zu verbessern ist was ich meine.
Phani
1
@Phani: AFAIK die 3. Form ist lediglich syntaktischer Zucker für die 2. Form (dh unter der Haube verwendet die foreach-Variante tatsächlich einen Iterator). Daher sollten für beide Varianten Leistungsvorteile verfügbar sein. Die erste Version würde natürlich keine Leistungsvorteile erhalten (z. B. wenn die Listals Baum implementiert ist, wäre sie tatsächlich langsamer).
MAK
36

Alle von ihnen haben ihre eigenen Verwendungszwecke:

  1. Wenn Sie eine iterable haben und bedingungslos zu allen von ihnen durchlaufen müssen:

    für (iterable_type iterable_element: collection)

  2. Wenn Sie eine iterable haben, aber bedingt durchlaufen müssen:

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

  3. Wenn die Datenstruktur nicht iterierbar implementiert:

    für (int i = 0; i <collection.length; i ++)

Suraj Chandran
quelle
Können Sie dies tun, um die erste Methode bedingt zu durchlaufen: if (iterable_element.some_attribute) {// etwas tun; } else {// nichts tun; }. Wenn ja, gibt es im Wesentlichen keinen Unterschied zwischen der ersten und der zweiten Methode, abgesehen von syntaktischem Zucker.
Thomas Nguyen
1 ist genauso in der Lage, bedingt zu durchqueren wie die anderen mit breakund / odercontinue
arcyqwerty
13

Es gibt zusätzlich den Stream () util von Sammlungen mit Java 8

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

oder

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

Weitere Informationen zu Java 8 Stream und Sammlungen für wonderers Link

snr
quelle
4

Keiner von ihnen ist "besser" als die anderen. Der dritte ist für mich besser lesbar, aber für jemanden, der keine Foreaches verwendet, könnte er seltsam aussehen (er könnte den ersten bevorzugen). Alle 3 sind für jeden, der Java versteht, ziemlich klar. Wählen Sie also, was Sie für den Code besser fühlen.

Das erste ist das grundlegendste, also das universellste Muster (funktioniert für Arrays, alle Iterables, die mir einfallen). Das ist der einzige Unterschied, den ich mir vorstellen kann. In komplizierteren Fällen (z. B. müssen Sie Zugriff auf den aktuellen Index haben oder die Liste filtern müssen) sind der erste und der zweite Fall möglicherweise sinnvoller. Für den einfachen Fall (iterierbares Objekt, keine besonderen Anforderungen) scheint der dritte der sauberste zu sein.

Rafe Kettler
quelle
2

Die erste Option ist eine bessere Leistung (da ArrayList die RandomAccess-Schnittstelle implementiert). Gemäß dem Java-Dokument sollte eine List-Implementierung die RandomAccess-Schnittstelle implementieren, wenn für typische Instanzen der Klasse diese Schleife gilt:

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

läuft schneller als diese Schleife:

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

Ich hoffe, es hilft. Die erste Option wäre für sequentielle Zugriffslisten langsam.

Amitav Padhi
quelle
1

Hier ist ein Beispiel

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

             }
Abdelouhab
quelle