Java: meilleur moyen d'itérer dans une collection (ici ArrayList)

98

Aujourd'hui, je codais volontiers quand je suis arrivé à un morceau de code que j'ai déjà utilisé des centaines de fois:

Itérer dans une collection (ici ArrayList)

Pour une raison quelconque, j'ai en fait examiné les options de saisie semi-automatique d'Eclipse et cela m'a fait me demander:

Dans quels cas les boucles suivantes sont-elles meilleures à utiliser que les autres?

La boucle d'index de tableau classique:

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

L'itérateur hasNext () / next ():

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

Et mon préféré parce que c'est si simple à écrire:

for (iterable_type iterable_element : collection) {

}
Jason Rogers
la source
2
Quand il s'agit de moi, j'utilise principalement la 3e boucle.
Harry Joy
1
Pour la deuxième façon, il vaut mieux utiliser:for (Iterator<type> iterator = collection.iterator(); iterator.hasNext();) { type type = iterator.next(); }
mike jones
4
L'interface de collection ne contient pas de méthode "get", donc la première n'est pas toujours possible.
ThePerson

Réponses:

104

Le premier est utile lorsque vous avez également besoin de l'index de l'élément. C'est fondamentalement équivalent aux deux autres variantes pour ArrayLists, mais sera vraiment lent si vous utilisez un LinkedList.

Le second est utile lorsque vous n'avez pas besoin de l'index de l'élément mais que vous devrez peut-être supprimer les éléments au fur et à mesure que vous itérez. Mais cela a l'inconvénient d'être un peu trop verbeux de l'OMI.

La troisième version est également mon choix préféré. Il est court et fonctionne pour tous les cas où vous n'avez besoin d'aucun index ou de l'itérateur sous-jacent (c'est-à-dire que vous n'accédez qu'aux éléments, ne les supprimez pas ou ne modifiez pas le Collectionde quelque manière que ce soit - ce qui est le cas le plus courant).

MAK
la source
3
+1 Battez-moi. allait mentionner LinkedList ( tous ne Collectionsont pas bon marché à récupérer par index).
The Scrum Meister
Tant qu'il suffit de boucler des éléments, il est toujours bon d'utiliser la 3e version, car l'implémentation existe déjà pour toutes les différentes collections et Sun ou toute implémentation JDK s'efforce d'améliorer les performances plutôt que chacune.
Phani
@Phani: Les deux autres variantes fonctionnent également sur n'importe quelle implémentation JDK.
MAK
Je n'ai pas dit que cela ne fonctionnerait pas, mais si, par hasard, certaines améliorations ou changements de performances étaient apportés aux implémentations de collections, cela s'appliquerait automatiquement à votre code et vous n'avez pas besoin d'écrire pour améliorer les performances. c'est ce que je veux dire.
Phani
1
@Phani: AFAIK la 3ème forme est simplement du sucre syntaxique pour la 2ème forme (c'est à dire sous le capot la variante foreach utilise en fait un itérateur). Les avantages de performance devraient donc être disponibles pour les deux variantes. La première version n'obtiendrait bien sûr aucun avantage en termes de performances (par exemple, si le Listest implémenté sous forme d'arborescence, ce serait en fait plus lent).
MAK
36

Tous ont leurs propres usages:

  1. Si vous avez un itérable et que vous devez les parcourir sans condition:

    pour (iterable_type iterable_element: collection)

  2. Si vous avez un itérable mais que vous devez le traverser conditionnellement:

    for (Itérateur itérateur = collection.iterator (); iterator.hasNext ();)

  3. Si la structure de données n'implémente pas l'itérable:

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

Suraj Chandran
la source
Pouvez-vous faire cela pour parcourir la première méthode conditionnellement: if (iterable_element.some_attribute) {// faire quelque chose; } else {// ne rien faire; }. Si oui, il n'y a essentiellement aucune différence entre la première et la deuxième méthode, autre que le sucre syntaxique.
Thomas Nguyen
1 est tout aussi capable de traverser conditionnellement que les autres en utilisant breaket / oucontinue
arcyqwerty
13

Il existe également un utilitaire stream () de collections avec Java 8

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

ou

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

Plus d'informations sur le lien Java 8 stream et collections for wonderers

snr
la source
4

Aucun d'eux n'est «meilleur» que les autres. Le troisième est, pour moi, plus lisible, mais pour quelqu'un qui n'utilise pas foreach, cela peut paraître étrange (ils préfèrent peut-être le premier). Tous les 3 sont assez clairs pour quiconque comprend Java, alors choisissez celui qui vous permet de vous sentir mieux dans le code.

Le premier est le plus basique, c'est donc le modèle le plus universel (fonctionne pour les tableaux, tous les itérables auxquels je peux penser). C'est la seule différence à laquelle je peux penser. Dans les cas plus compliqués (par exemple, vous devez avoir accès à l'index actuel, ou vous devez filtrer la liste), les premier et deuxième cas peuvent avoir plus de sens, respectivement. Pour le cas simple (objet itérable, pas d'exigences particulières), le troisième semble le plus propre.

Rafe Kettler
la source
2

La première option est de meilleures performances (car ArrayList implémente l'interface RandomAccess). Selon la documentation java, une implémentation de List doit implémenter l'interface RandomAccess si, pour des instances typiques de la classe, cette boucle:

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

s'exécute plus vite que cette boucle:

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

J'espère que cela aide. La première option serait lente pour les listes d'accès séquentielles.

Amitav Padhi
la source
1

Voici un exemple

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
la source