web-dev-qa-db-fra.com

Pourquoi avons-nous besoin d'utiliser itérateur sur ArrayList en Java?

Je lisais la réponse à la question " Avons-nous jamais besoin d'utiliser des itérateurs sur ArrayList? ".

Dans la réponse, l'utilisateur a déclaré quelque chose comme ceci: "Un cas d'utilisation important d'itérateurs avec ArrayLists consiste à supprimer des éléments lors d'une itération".

Ceci pourrait être réalisé même en utilisant la méthode remove de ArrayList en Java. Ma question est pourquoi nous avons besoin d'un itérateur dans ArrayList? 

Considérons le code: 

import Java.util.*;
public class ocajp66 {
    public static void main(String[] args) {
        ArrayList a = new ArrayList();
        for (int i = 0; i < 10; i++) {
            a.add(i);
        }
        System.out.printf("BEFORE ITERATOR\n");
        for (int i = 0; i < a.size(); i++) {
            System.out.printf("I:%d\n", a.get(i));
        }
        System.out.printf("AFTER ITERATOR\n");
        Iterator i = a.iterator();
        while (i.hasNext()) {
            System.out.printf("I:%d\n", i.next());
        }
    }
}

Quelqu'un peut-il expliquer la signification de l'itérateur? Ce serait merveilleux si vous pouviez m'expliquer avec du code.

32
Karthik Rk

Comme vous l'avez dit, itérateur est utilisé lorsque vous souhaitez supprimer des éléments pendant que vous parcourez le contenu du tableau. Si vous n'utilisez pas d'itérateur mais simplement une boucle for et que vous utilisez la méthode remove à l'intérieur, vous obtiendrez des exceptions car le contenu du tableau change en cours d'itération. Par exemple: vous pourriez penser que la taille du tableau est 10 au début de la boucle for, mais ce ne sera pas le cas une fois que vous supprimerez des éléments. Ainsi, si vous atteignez les dernières boucles, il y aura probablement IndexOutofBoundsException, etc.

49
Dev Blanked

Il est clair qu'une API de type ArrayList- pourrait fonctionner sans la méthode iterator(). Cependant, une ArrayList est une Collection et la méthode iterator() est définie dans l'interface Collection ... donc ArrayList doit pour l'implémenter.

Le point à propos de la suppression d'une ArrayList est que le faire par indexation nécessite une réflexion:

    for (int i = 0; 
         i < a.size(); // Hoist this at your peril
         i++) {
        if (a.get(i) == something) {
            a.remove(i);
            i--;  // Leave this out at your peril
        }
    }

Et cela empire si vous devez supprimer l'élément de la liste dans une méthode appelée de la boucle ... car la méthode doit ensuite indiquer qu'elle a supprimé un élément afin que l'appelant puisse ajuster l'index de la boucle.

Une troisième raison pour laquelle iterator est une bonne chose sur une ArrayList est qu’elle vous permet d’utiliser la syntaxe for (type var : iterable) ... de Java 5.

L'essentiel est que vous n'avez pas à utiliser les itérateurs sur les instances ArrayList. Si vous ne voulez pas, alors ne le faites pas.

14
Stephen C

Ceci est un exemple de la façon dont il est possible d’obtenir les résultats souhaités de différentes manières. Ce type de redondance n'est pas propre à Java.

  • pour (int i = 0; i <myArray.length; i ++) {...}

Cette syntaxe a été introduite dans les toutes premières versions de Java. Il itère sur un tableau Java habituel dans une boucle for {}. Cela est généralement sûr car les tableaux Java ont une longueur fixe et que les exceptions "Index Out of Bounds" ne sont pas possibles.

  • for (int i = 0; i <myArrayList.size (); i ++ {...}

Cette syntaxe reflète une version ultérieure de Java, après l'introduction de l'API Collections qui introduisait ArrayList. Les classes qui implémentent l'interface Collection, comme déjà mentionné ci-dessus, doivent implémenter un Iterator mais vous n'êtes pas obligé de l'utiliser. Ce n'est pas le cas pour la boucle {}, mais le danger ici est que les ArrayLists ne sont pas de taille fixe. Si cela devait diminuer dans le corps de votre boucle for, des exceptions pourraient en résulter.

  • pour (MyArrayType t: myArrayList) {}

Cette syntaxe a également été publiée dans une version ultérieure de Java. C'est ce qu'on appelle la boucle améliorée. Toute classe de collection qui fournit un Iterator en implémentant l'interface Iterable peut tirer parti de cette syntaxe. Cela permet d'itérer sur les éléments d'une collection sans avoir à instancier explicitement un Iterator. Une méthode favorite pour utiliser cela dans une application JavaFX consiste à parcourir en boucle un groupe de contrôles pour définir une propriété sur une valeur, par exemple. Pour réinitialiser le contenu d'un groupe de TextFields:

for (TextField tf : new TextField[] { txtf1, txtf2, txtf3, txtfa, txtfb, txtfc}) {
    tf.setText("");
}
  • while (myCollectionIterator.hasNext ()) {}

Vous pouvez toujours explicitement instancier un Iterator. Cette option est sans danger lorsque la taille de la collection change (à partir des méthodes propres à la collection). Il est correct de dire que l'Iterator est plus étroitement une propriété de l'interface Iterable qu'une fonctionnalité du langage Java principal. Mais vous pouvez toujours l'utiliser comme une fonctionnalité de type langage (dans la boucle for améliorée) grâce aux versions ultérieures de Java.

Ces constructions fournissent une redondance, mais elles ne sont pas identiques. Il existe des nuances qui permettent d’être particulièrement utile à un moment donné. Vous devriez les utiliser tous.

6
scottb

Q: Pourquoi avons-nous besoin d'un itérateur dans ArrayList?

Nous ne le faisons pas - comme vous l'avez montré dans votre code, vous pouvez effectuer une itération et effectuer des opérations de base sur un ArrayList sans itérateur. Mais c'est agréable d'avoir une fonctionnalité.

Q: Quelqu'un peut-il expliquer la signification de l'itérateur?

En plus de sa valeur de conception, j’ai pu le constater, c’est sa fonction d’échec rapide. Je cite ce paragraphe de la documentation ArrayList :

Les itérateurs retournés par les itérateurs et listIterator de cette classe les méthodes sont fail-fast: si la liste est structurellement modifiée à n’importe quel fichier temps après la création de l'itérateur, de quelque manière que ce soit, sauf par le biais du fichier les méthodes de suppression ou d’ajout de l’itérateur, l’itérateur jettera un ConcurrentModificationException. Ainsi, face à concurrente modification, l'itérateur échoue rapidement et proprement, plutôt que risque de comportement arbitraire et non déterministe à un moment indéterminé A l'avenir.

Vous cherchiez du code, vous pouvez voir l'implémentation de l'itérateur de ArrayList ici: ArrayList.Java .

1
Jops

Pour votre question, si nous utilisons la méthode list.remove() au lieu de iterator.remove(), alors IndexOutOfBoundsException sera lancé. 

list.remove() est sûr à utiliser si vous mettez l'instruction break une fois que vous avez trouvé un objet/index spécifique à supprimer, afin qu'il soit quitté de la boucle sans aucune exception (comme IndexOutOfBoundsException)

Suivre le code itérateur peut toujours renvoyerConcurrentModificationException si nous utilisons l’itérateur EVEN dans un environnement synchronized.

List<String> empNames = new ArrayList<String>();
        synchronized (empNames) {
            Iterator<String> iterator = empNames.iterator();
            while (iterator.hasNext()) {
                iterator.next();
                empNames.add("Another Name"); // throws
                // ConcurrentModificationException
            }
        }
0
AmitG