1. Contexte de la création des itérateurs

Vous connaissez déjà HashSet. Si vous l'avez vraiment étudié, au-delà de la simple lecture d'une leçon, vous auriez dû poser cette question :

Comment afficher une liste de tous les éléments HashSet à l'écran ? Après tout, l'interface n'a pas get()de set()méthodes !

Et HashSetn'est pas seul dans cette limitation. En plus de HashSet, il existe de nombreuses autres collections qui n'autorisent pas la récupération des éléments par index, car les éléments n'ont pas d'ordre défini.

Au fil des ans, les programmeurs ont inventé de nombreuses structures de données complexes, telles que des graphiques et des arbres. Ou des listes de listes.

De nombreux conteneurs modifient l'ordre de leurs éléments lorsque de nouveaux éléments sont ajoutés ou que des éléments existants sont supprimés. Par exemple, une liste stocke les éléments dans un ordre particulier, et lorsqu'un nouvel élément est ajouté, il est presque toujours inséré au milieu de la liste.

Et nous obtenons également des situations où il y a un conteneur qui stocke des éléments mais pas dans un ordre fixe.

Supposons maintenant que nous voulions copier tous les éléments d'une telle collection dans un tableau ou une liste. Nous devons obtenir tous les éléments. Nous ne nous soucions pas de l'ordre dans lequel nous parcourons les éléments - l'important est de ne pas parcourir les mêmes éléments plus d'une fois. Comment fait-on cela?


2. Itérateur pour une collection

Les itérateurs ont été proposés comme solution au problème ci-dessus.

Un itérateur est un objet spécial associé à une collection, qui permet de parcourir tous les éléments de la collection sans en répéter aucun.

Vous pouvez utiliser le code suivant pour obtenir un itérateur pour n'importe quelle collection :

Iterator<Type> it = name.iterator();

nameest le nom de la variable de collection, Typeest le type des éléments de la collection, iterator()est l'une des méthodes de la collection et itest le nom de la variable d'itérateur.

Un objet itérateur a 3 méthodes :

Méthode Description
Type next()
Renvoie l'élément suivant de la collection
boolean hasNext()
Vérifie s'il y a des éléments qui n'ont pas encore été parcourus
void remove()
Supprime l'élément courant de la collection

nextInt)Ces méthodes sont quelque peu similaires aux méthodes et à la classe Scanner hasNextInt().

La next()méthode renvoie l'élément suivant de la collection à partir de laquelle nous avons obtenu l'itérateur.

La hasNext()méthode vérifie si la collection contient des éléments supplémentaires que l'itérateur n'a pas encore renvoyés.

Voici comment afficher tous les éléments d'un HashSet:

Code Remarques
HashSet<String> set = new HashSet<String>();

set.add("Hallo");
set.add("Hello");
set.add("Hola");
set.add("Bonjour");
set.add("Ciao");
set.add("Namaste");

Iterator<String> it = set.iterator();
while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}
Créez un HashSetobjet qui stocke Stringdes éléments.


Nous ajoutons des salutations dans différentes langues à la setvariable.




Obtenez un objet itérateur pour l' setensemble.
Tant qu'il reste des éléments

Obtenir l'élément suivant
Afficher l'élément à l'écran


3. For-eachboucle

Le principal inconvénient d'un itérateur est que votre code devient plus lourd que d'utiliser une forboucle.

Pour comparer, affichons une liste à l'aide d'une forboucle et également à l'aide d'un itérateur :

Itérateur pour la boucle
ArrayList<String> list = new ArrayList<String>();

Iterator<String> it = list.iterator();
while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();

for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);
   System.out.println(str);
}

Oui, c'est bien mieux de parcourir les éléments d'un en ArrayListutilisant une boucle — tout s'avère plus court.

Mais les créateurs de Java ont de nouveau décidé de nous verser du sucre. Heureusement pour nous, c'était du sucre syntaxique .

Ils ont donné à Java un nouveau type de boucle et l'ont appelé une for-eachboucle. Voici à quoi ça ressemble en général:

for(Type name:collection)

collectionest le nom de la variable de collection, Typeest le type des éléments de la collection et nameest le nom d'une variable qui prend la valeur suivante de la collection à chaque itération de la boucle.

Ce type de boucle parcourt tous les éléments d'une collection à l'aide d'un itérateur implicite. Voici comment cela fonctionne réellement :

Boucle pour chaque Ce que le compilateur voit : Boucle avec un itérateur
ArrayList<String> list = new ArrayList<String>();

for (String str: list)
{
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();
Iterator<String> it = list.iterator();

while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}

Lorsque le compilateur rencontre une for-eachboucle dans votre code, il la remplace simplement par le code de droite : il ajoute un appel pour obtenir un itérateur avec tout autre appel de méthode manquant.

Les programmeurs adorent la for-eachboucle et l'utilisent presque toujours lorsqu'ils doivent itérer sur tous les éléments d'une collection.

Même l'itération sur une ArrayListliste à l'aide d'une for-eachboucle semble plus courte :

Boucle pour chaque pour la boucle
ArrayList<String> list = new ArrayList<String>();

for (String str: list)
{
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();

for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);
   System.out.println(str);
}


4. Supprimer un élément dans une for-eachboucle

La for-eachboucle a un inconvénient : elle ne peut pas supprimer correctement les éléments. Si vous écrivez un code comme celui-ci, vous obtiendrez une erreur.

Code Note
ArrayList<String> list = new ArrayList<String>();

list.add("Hallo");
list.add("Hello");
list.add("Hola");
list.add("Bonjour");
list.add("Ciao");
list.add("Namaste");

for (String str: list)
{
   if (str.equals("Hello"))
      list.remove(str);
}












L'opération de suppression générera une erreur !

C'est un code très agréable et compréhensible, mais cela ne fonctionnera pas.

Important!

Vous ne pouvez pas modifier une collection pendant que vous la parcourez avec un itérateur.

Il existe trois façons de contourner cette limitation.

1. Utilisez un autre type de boucle

When traversing an ArrayList collection, vous pouvez utiliser une boucle ordinaire avec une ivariable compteur.

Code
for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);

   if (str.equals("Hello"))
   {
      list.remove(str);
      i--; // We need to decrease i, because the remove operation shifted the elements
   }
}

Cependant, cette option n'est pas adaptée aux collections HashSetetHashMap

2. Utilisez un itérateur explicite

Vous pouvez utiliser un itérateur explicitement et appeler sa remove()méthode.

Version qui fonctionne Version qui ne fonctionne pas
Iterator<String> it = set.iterator();
while (it.hasNext())
{
   String str = it.next();
   if (str.equals("Hello"))
       it.remove();
}

for (String str: list) { if (str.equals("Hello")) list.remove(str); }

Notez que nous appelons la remove()méthode sur l'objet itérateur ! L'itérateur est conscient que l'élément a été supprimé et peut gérer la situation correctement.

3. Utilisez une copie de la collection

Vous pouvez également créer une copie de la collection, puis utiliser la copie dans une for-eachboucle et supprimer des éléments de la collection d'origine.

Code Note
ArrayList<String> listCopy = new ArrayList(list);

for (String str: listCopy)
{
   if (str.equals("Hello"))
      list.remove(str);
}
Créer une copie d'une collection est super facile



La boucle utilise l'itérateur pour la copie de la collection.
Les éléments sont supprimés de la listcollection.

La collection est copiée assez rapidement, car les éléments eux-mêmes ne sont pas dupliqués. Au lieu de cela, la nouvelle collection stocke les références aux éléments qui existent déjà dans l'ancienne collection.