Maison >Java >javaDidacticiel >Explication détaillée de la boucle for-each et de l'itération en JAVA
Lors de l'apprentissage de la collection en Java, j'ai remarqué que l'interface racine Collection du niveau collection implémente l'interface Iterable8742468051c85b06f0a0af9e3e506b5c (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 : Iterator8742468051c85b06f0a0af9e3e506b5c
public interface Iterator<E>{ boolean hasNext(); E next(); void remove(); }
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 Iterator8742468051c85b06f0a0af9e3e506b5c 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 } } }
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 Iterator8742468051c85b06f0a0af9e3e506b5c
À 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 Iterable8742468051c85b06f0a0af9e3e506b5c
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); } } }
Le code ci-dessus ne sera pas compilé car la classe CustomCollection dans le code n'implémente pas l'interface Iterable8742468051c85b06f0a0af9e3e506b5c 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 Iterable8742468051c85b06f0a0af9e3e506b5c É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(); } } }
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); } } }
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 !