Dites que j'ai une liste comme:
List<String> list = new ArrayList<>();
list.add("a");
list.add("h");
list.add("f");
list.add("s");
En parcourant cette liste, je souhaite ajouter un élément à la fin de la liste. Mais je ne veux pas parcourir les éléments récemment ajoutés, c’est-à-dire jusqu’à la taille initiale de la liste.
for (String s : list)
/* Here I want to add new element if needed while iterating */
Quelqu'un peut-il me suggérer comment puis-je faire cela?
Vous ne pouvez pas utiliser une déclaration foreach pour cela. Le foreach utilise en interne un itérateur:
Les itérateurs retournés par les méthodes iterator et listIterator de cette classe sont ultra-rapides: si la liste est structurellement modifiée à tout moment après la création de l'itérateur, de quelque manière que ce soit, sauf par le biais de ses propres méthodes remove et add, l'itérateur lève une exception ConcurrentModificationException.
(De ArrayList javadoc)
Dans l'instruction foreach, vous n'avez pas accès à la méthode add de l'itérateur et, dans tous les cas, ce n'est toujours pas le type d'ajout souhaité car il n'est pas ajouté à la fin. Vous devrez parcourir la liste manuellement:
int listSize = list.size();
for(int i = 0; i < listSize; ++i)
list.add("whatever");
Notez que cela n’est efficace que pour les listes autorisant l’accès aléatoire. Vous pouvez vérifier cette fonctionnalité en vérifiant si la liste implémente l'interface du marqueur RandomAccess. Un ArrayList a un accès aléatoire. Une liste chaînée ne fait pas.
Parcourez une copie de la liste et ajoutez de nouveaux éléments à la liste d'origine.
for (String s : new ArrayList<String>(list))
{
list.add("u");
}
Voir Comment faire une copie d'un objet ArrayList qui est un type de liste?
Il suffit de réitérer la méthode habituelle, car vous avez besoin d'une gestion explicite des index:
List myList = ...
...
int length = myList.size();
for(int i = 0; i < length; i++) {
String s = myList.get(i);
// add items here, if you want to
}
Vous pouvez itérer sur une copie (clone) de votre liste d'origine:
List<String> copy = new ArrayList<String>(list);
for (String s : copy) {
// And if you have to add an element to the list, add it to the original one:
list.add("some element");
}
Notez qu'il n'est même pas possible d'ajouter un nouvel élément à une liste lors d'une itération sur celle-ci, car il en résulterait un ConcurrentModificationException
.
Je le fais en ajoutant les éléments à une nouvelle liste tmp vide, puis en ajoutant la liste tmp à la liste d'origine à l'aide de addAll()
. Cela évite de copier inutilement une grande liste de sources.
Imaginez ce qui se passe lorsque la liste originale du PO contient quelques millions d'éléments. pendant un moment, vous allez aspirer deux fois plus de mémoire.
En plus de la conservation des ressources, cette technique nous évite également d'avoir à recourir à des boucles à la manière des années 80 et à utiliser des index de tableau qui pourraient être peu attrayants dans certains cas.