Maison > Java > javaDidacticiel > Explication détaillée de la boucle for-each et de l'itération en JAVA

Explication détaillée de la boucle for-each et de l'itération en JAVA

高洛峰
Libérer: 2017-01-21 16:43:06
original
1403 Les gens l'ont consulté

Lors de l'apprentissage de la collection en Java, j'ai remarqué que l'interface racine Collection du niveau collection implémente l'interface Iterable (située dans le package java.lang). foreach", et cette La seule méthode implémentée dans l'interface est de renvoyer un itérateur qui itère sur un ensemble d'éléments de type T.

1. Iterator Iterator

Interface : Iterator

public interface Iterator<E>{
  boolean hasNext();
 E next();
 void remove();
 }
Copier après la connexion

En regardant l'API de l'interface Iterator, vous pouvez savoir qu'il s'agit d'un itérateur pour parcourir la collection. Les itérateurs permettent à l'appelant de supprimer des éléments de la collection pointée par l'itérateur lors de l'itération en utilisant une sémantique bien définie.

Il convient de noter en particulier l'utilisation de la méthode Remove() de cet itérateur : supprimer le dernier élément renvoyé par l'itérateur (opération facultative) de la collection pointée par l'itérateur. Cette méthode ne peut être appelée qu'une seule fois par appel au suivant. Si la collection pointée par l'itérateur est modifiée lors d'une itération autrement qu'en appelant cette méthode (méthode Remove), le comportement de l'itérateur n'est pas défini. Le concepteur de l'interface a souligné lors de la conception de l'interface Iterator que si la méthode remove() autre que l'itérateur est appelée pour modifier la collection pointée par l'itérateur pendant l'itération, cela entraînera des conséquences incertaines. Les conséquences spécifiques dépendent de l’implémentation spécifique de l’itérateur. En réponse aux situations possibles où de telles conséquences incertaines peuvent survenir, j'en ai rencontré une lors de l'apprentissage d'ArrayList : l'itérateur a lancé une exception ConcurrentModificationException. La situation d'exception spécifique est indiquée dans le code suivant :

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
public class ItaratorTest {
 
  public static void main(String[] args) {
    Collection<String> list = new ArrayList<String>();
    list.add("Android");
    list.add("IOS");
    list.add("Windows Mobile");
 
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
      String lang = iterator.next();
      list.remove(lang);//will throw ConcurrentModificationException
    }
  }
 
}
Copier après la connexion

Ce code lancera une exception ConcurrentModificationException lors de l'exécution, car nous n'en avons aucune utilité pendant l'itérateur. exécutez la méthode Remove() de l'itérateur pour supprimer des éléments, mais utilisez la méthode Remove() de ArrayList pour modifier la collection pointée par l'itérateur. Cela viole les principes de conception des itérateurs, donc une exception se produit.

L'exception signalée est la suivante :

Exception dans le fil "main" java.util.ConcurrentModificationException
à java.util.ArrayList$Itr.checkForComodification ( ArrayList.java:859)
à java.util.ArrayList$Itr.next(ArrayList.java:831)
à Text.ItaratorTest.main(ItaratorTest.java:17)

2. boucle for-each et itérateur Iterator

À partir de Java5, il existe une boucle for-each en Java, qui peut être utilisée pour parcourir des collections et des tableaux. La boucle Foreach vous permet de parcourir la collection sans conserver l'index dans une boucle for traditionnelle, ou sans appeler la méthode hasNext() dans la boucle while lors de l'utilisation de l'itérateur/ListIterator (une implémentation d'itérateur dans ArrayList). La boucle for-each simplifie le processus de parcours de n'importe quelle collection ou tableau. Mais il y a deux points à noter lors de l’utilisation d’une boucle foreach.

Les objets utilisant la boucle foreach doivent implémenter l'interface Iterable

Veuillez consulter l'exemple suivant :

import java.util.ArrayList;
 
public class ForeachTest1 {
 
  public static void main(String args[]) {
    CustomCollection<String> myCollection = new CustomCollection<String>();
    myCollection.add("Java");
    myCollection.add("Scala");
    myCollection.add("Groovy");
 
    // What does this code will do, print language, throw exception or
    // compile time error
    for (String language : myCollection) {
      System.out.println(language);
    }
  }
 
  private class CustomCollection<T> {
    private ArrayList<T> bucket;
 
    public CustomCollection() {
      bucket = new ArrayList();
    }
 
    public int size() {
      return bucket.size();
    }
 
    public boolean isEmpty() {
      return bucket.isEmpty();
    }
 
    public boolean contains(T o) {
      return bucket.contains(o);
    }
 
    public boolean add(T e) {
      return bucket.add(e);
    }
 
    public boolean remove(T o) {
      return bucket.remove(o);
    }
 
  }
}
Copier après la connexion

Le code ci-dessus ne sera pas compilé car la classe CustomCollection dans le code n'implémente pas l'interface Iterable L'erreur signalée lors de la compilation est la suivante :

Exception dans le fil de discussion ". main" java .lang.Error : problème de compilation non résolu :
Ne peut parcourir qu'un tableau ou une instance de java.lang.Iterable

à Text.ForeachTest1.main(ForeachTest1.java:15)

En fait, il n'est pas nécessaire d'attendre la compilation pour trouver l'erreur. Eclipse affichera l'erreur dans la boucle foreach après avoir écrit ce code : Ne peut itérer que sur un tableau ou une instance de java. lang.Iterable

Ce qui peut être confirmé à nouveau à partir de l'exemple ci-dessus, c'est que la boucle foreach s'applique uniquement aux objets qui implémentent l'interface Iterable Étant donné que toutes les classes Collection intégrées implémentent l'interface java.util.Collection et ont hérité d'Iterable, afin de résoudre les problèmes ci-dessus, vous pouvez choisir de simplement laisser CustomCollection implémenter l'interface Collection ou d'hériter de AbstractCollection. La solution est la suivante :

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Iterator;
 
public class ForeachTest {
  public static void main(String args[]) {
    CustomCollection<String> myCollection = new CustomCollection<String>();
    myCollection.add("Java");
    myCollection.add("Scala");
    myCollection.add("Groovy");
    for (String language : myCollection) {
      System.out.println(language);
    }
  }
 
  private static class CustomCollection<T> extends AbstractCollection<T> {
    private ArrayList<T> bucket;
 
    public CustomCollection() {
      bucket = new ArrayList();
    }
 
    public int size() {
      return bucket.size();
    }
 
    public boolean isEmpty() {
      return bucket.isEmpty();
    }
 
    public boolean contains(Object o) {
      return bucket.contains(o);
    }
 
    public boolean add(T e) {
      return bucket.add(e);
    }
 
    public boolean remove(Object o) {
      return bucket.remove(o);
    }
 
    @Override
    public Iterator<T> iterator() {
      // TODO Auto-generated method stub
      return bucket.iterator();
    }
  }
}
Copier après la connexion

2. L'implémentation interne de la boucle foreach s'appuie également sur Iterator

Afin de vérifier que la boucle foreach utilise Iterator. comme implémentation interne de ceci. En fait, nous utilisons toujours l'exemple au début de cet article pour vérification :

public class ItaratorTest {
 
  public static void main(String[] args) {
    Collection<String> list = new ArrayList<String>();
    list.add("Android");
    list.add("IOS");
    list.add("Windows Mobile");
 
    // example1
    // Iterator<String> iterator = list.iterator();
    // while (iterator.hasNext()) {
    // String lang = iterator.next();
    // list.remove(lang);
    // }
 
    // example 2
    for (String language : list) {
      list.remove(language);
    }
  }
 
}
Copier après la connexion

Exception signalée lors de l'exécution du programme :

Exception dans le fil de discussion "main" java.util.ConcurrentModificationException
à java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
à java.util.ArrayList$Itr.next( ArrayList.java:831)
at Text .ItaratorTest.main(ItaratorTest.java:22)

Cette exception montre que l'itérateur est utilisé à l'intérieur de la boucle for-each pour parcourir la collection It. appelle également Iterator.next(), qui vérifie (de l'élément) les modifications et renvoie ConcurrentModificationException.

Résumé :

Lors du parcours d'une collection, si vous souhaitez modifier la collection pendant le parcours, vous devez le faire via Iterator/listIterator, sinon des "conséquences indéterminées" peuvent survenir.

La boucle foreach est implémentée via l'itérateur. L'objet utilisant la boucle foreach doit implémenter l'interface Iterable

Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'apprentissage de chacun. J'espère également que tout le monde soutiendra le site Web PHP chinois.

Pour des articles plus détaillés sur la boucle for-each et l'itération en JAVA, veuillez faire attention au site Web PHP chinois !


Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal