Question Itérateur vs pour


On m'a demandé dans une interview quel était l'avantage d'utiliser l'itérateur en utilisant pour la boucle ou quel est l'avantage d'utiliser pour itérateur en boucle?

Est-ce que n'importe quel corps peut répondre à cela pour qu'à l'avenir Si je fais face à une question similaire alors je peux répondre à cela


44
2018-03-08 10:09


origine


Réponses:


Tout d'abord, il existe 2 types de boucles for qui se comportent très différemment. On utilise des indices:

for (int i = 0; i < list.size(); i++) {
    Thing t = list.get(i);
    ...
}

Ce type de boucle n'est pas toujours possible. Par exemple, les listes ont des index, mais les ensembles ne le sont pas, car elles ne sont pas ordonnées.

L'autre, la boucle foreach utilise un itérateur en coulisse:

for (Thing thing : list) {
    ...
}

Cela fonctionne avec tout type de collection Iterable (ou tableau)

Et enfin, vous pouvez utiliser un itérateur, qui fonctionne également avec toutes les itérations:

for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
    Thing t = it.next();
    ...
} 

Vous avez donc 3 boucles à comparer.

Vous pouvez les comparer en différents termes: performance, lisibilité, sensibilité aux erreurs, capacité.

Un itérateur peut faire des choses qu'une boucle foreach ne peut pas faire. Par exemple, vous pouvez supprimer des éléments pendant l’itération, si l’itérateur le prend en charge:

for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
    Thing t = it.next();
    if (shouldBeDeleted(thing) {
        it.remove();
    }
} 

Les listes offrent également des itérateurs pouvant itérer dans les deux sens. Une boucle foreach ne se répète que du début à la fin.

Mais un itérateur est plus dangereux et moins lisible. Lorsqu'une boucle foreach est tout ce dont vous avez besoin, c'est la solution la plus lisible. Avec un itérateur, vous pouvez faire ce qui suit, ce qui serait un bug:

for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
    System.out.println(it.next().getFoo());
    System.out.println(it.next().getBar());
} 

Une boucle foreach ne permet pas qu'un tel bug se produise.

L'utilisation des index pour accéder aux éléments est légèrement plus efficace avec les collections sauvegardées par un tableau. Mais si vous changez d'avis et utilisez une LinkedList au lieu d'une ArrayList, soudain, les performances seront terribles, car chaque fois que vous accédez à list.get(i), la liste liée devra parcourir tous ses éléments jusqu’à la Un itérateur (et donc la boucle foreach) n'a pas ce problème. Il utilise toujours le meilleur moyen possible pour parcourir les éléments de la collection donnée, car la collection elle-même a sa propre implémentation Iterator.

Ma règle générale est la suivante: utilisez la boucle foreach, sauf si vous avez vraiment besoin des capacités d'un itérateur. Je n'utiliserais que pour la boucle avec des index avec des tableaux, quand j'ai besoin d'accéder à l'index dans la boucle.


80
2018-03-08 10:47



Avantage Itérateur:

  • Possibilité de supprimer des éléments des collections.
  • Possibilité d'avancer et de reculer en utilisant next() et previous().
  • Possibilité de vérifier s'il y a plus d'éléments ou non en utilisant hasNext().

La boucle a été conçue uniquement pour parcourir une Collection, donc si vous voulez juste itérer sur un Collection, il vaut mieux utiliser une boucle telle que for-Each, mais si vous en voulez plus, vous pouvez utiliser Iterator.


13
2018-03-08 10:15



Si vous accédez aux données par numéro (par exemple "i"), il est rapide lorsque vous utilisez un tableau. parce qu'il va directement à l'élément

Mais, autre structure de données (par exemple, arbre, liste), elle nécessite plus de temps, car elle part du premier élément vers l'élément cible. lorsque vous utilisez la liste. Il a besoin de temps O (n). alors, ça doit être lent.

Si vous utilisez un itérateur, le compilateur sait où vous êtes. donc il faut O (1) (parce que ça commence à partir de la position actuelle)

enfin, si vous utilisez uniquement un tableau ou une structure de données prenant en charge un accès direct (par exemple, arraylist à java). "a [i]" est bon. mais, lorsque vous utilisez une autre structure de données, l'itérateur est plus efficace


10
2018-03-08 10:17



La principale différence entre Iterator et le classic for loop, mis à part le fait évident d’avoir ou de ne pas avoir accès à l’index de l’itération, est que l’utilisation de Iterator abstrait le code client de l’implémentation sous-jacente de la collection. élaborer.

Lorsque votre code utilise un itérateur, soit sous cette forme

for(Item element : myCollection) { ... }

ce formulaire

Iterator<Item> iterator = myCollection.iterator();
while(iterator.hasNext()) {    
    Item element = iterator.next();    
    ... 
}

ou cette forme

for(Iterator iterator = myCollection.iterator(); iterator.hasNext(); ) {
   Item element = iterator.next();
   ...
}

Ce que votre code dit, c’est que «je ne me soucie pas du type de collection et de sa mise en œuvre, je me soucie simplement de pouvoir parcourir ses éléments». Ce qui est généralement la meilleure approche, car cela rend votre code plus découplé.

Par contre, si vous utilisez le classique pour la boucle, comme dans

for(int i = 0; i < myCollection.size(); i++) {
   Item element = myCollection.get(i);
   ...
}

Votre code dit, j'ai besoin de connaître le type de collection, car je dois parcourir ses éléments de manière spécifique, je vais aussi vérifier les valeurs NULL ou calculer un résultat en fonction de l'ordre d'itération. Ce qui rend votre code plus fragile, car si, à tout moment, le type de collection que vous recevez change, cela affectera le fonctionnement de votre code.

En résumé, la différence n'est pas tellement la vitesse ou l'utilisation de la mémoire, mais plutôt le découplage de votre code afin qu'il soit plus flexible pour faire face aux changements.


6
2018-03-08 12:28