Étant un peu nouveau dans le langage Java, j'essaie de me familiariser avec toutes les façons (ou au moins celles non pathologiques) que l'on pourrait parcourir à travers une liste (ou peut-être d'autres collections) et les avantages ou les inconvénients de chacun.
Étant donné un List<E> list
objet, je connais les façons suivantes de parcourir tous les éléments:
De base pour la boucle (bien sûr, il existe également des boucles while
/ équivalentes do while
)
// Not recommended (see below)!
for (int i = 0; i < list.size(); i++) {
E element = list.get(i);
// 1 - can call methods of element
// 2 - can use 'i' to make index-based calls to methods of list
// ...
}
Remarque: Comme @amarseillan l'a souligné, ce formulaire est un mauvais choix pour itérer sur List
s, car l'implémentation réelle de la get
méthode peut ne pas être aussi efficace que lors de l'utilisation d'un Iterator
. Par exemple, les LinkedList
implémentations doivent traverser tous les éléments précédant i pour obtenir le i-ème élément.
Dans l'exemple ci-dessus, l' List
implémentation n'a aucun moyen de "sauver sa place" pour rendre les futures itérations plus efficaces. Pour un, ArrayList
cela n'a pas vraiment d'importance, car la complexité / le coût de get
est un temps constant (O (1)) tandis que pour un LinkedList
il est proportionnel à la taille de la liste (O (n)).
Pour plus d'informations sur la complexité de calcul des Collections
implémentations intégrées , consultez cette question .
Amélioré pour la boucle (bien expliqué dans cette question )
for (E element : list) {
// 1 - can call methods of element
// ...
}
Itérateur
for (Iterator<E> iter = list.iterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// ...
}
ListIterator
for (ListIterator<E> iter = list.listIterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// 3 - can use iter.add(...) to insert a new element into the list
// between element and iter->next()
// 4 - can use iter.set(...) to replace the current element
// ...
}
Java fonctionnel
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach , Stream.forEach , ...
(Une méthode de carte de l'API Stream de Java 8 (voir la réponse de @ i_am_zero).)
Dans Java 8, les classes de collection qui implémentent Iterable
(par exemple, tous les List
s) ont désormais une forEach
méthode, qui peut être utilisée à la place de l' instruction for loop illustrée ci-dessus. (Voici une autre question qui fournit une bonne comparaison.)
Arrays.asList(1,2,3,4).forEach(System.out::println);
// 1 - can call methods of an element
// 2 - would need reference to containing object to remove an item
// (TODO: someone please confirm / deny this)
// 3 - functionally separates iteration from the action
// being performed with each item.
Arrays.asList(1,2,3,4).stream().forEach(System.out::println);
// Same capabilities as above plus potentially greater
// utilization of parallelism
// (caution: consequently, order of execution is not guaranteed,
// see [Stream.forEachOrdered][stream-foreach-ordered] for more
// information about this).
Quels autres moyens existe-t-il, le cas échéant?
(BTW, mon intérêt ne découle pas du tout d'un désir d' optimiser les performances ; je veux juste savoir quelles formes sont à ma disposition en tant que développeur.)
List
interface est-elle spécifique?