En Java, la boucle for-each simplifie le processus de parcours de toute collection ou tableau, mais tous les programmeurs Java ne connaissent pas certains détails de la boucle for-each qui seront décrits dans cet article. Contrairement aux autres termes publiés dans Java 5 : génériques publiés par alias, encapsulation automatique et paramètres variadiques, les développeurs Java utilisent les boucles for-each plus fréquemment que toute autre fonctionnalité, mais lorsqu'on leur demande comment fonctionnent les boucles for-each avancées, ou quelles sont les fonctions de base exigences lors de l’utilisation d’une collection dans une boucle for-each, tout le monde ne peut pas y répondre.
Ce didacticiel et cet exemple visent à combler cette lacune en abordant quelques énigmes intéressantes dans les boucles for-each. Bon, n'entrons pas dans les détails, jetons un coup d'œil à notre premier problème avec la boucle for-each Java5.
Question de boucle avancée 1
Considérez le code suivant qui traverse un agrégateur ou une classe de collection définie par l'utilisateur. Qu'imprimera ce code, qu'il génère une exception ou une erreur du compilateur :
Copiez le code comme suit :
test de paquet ;
/**
* Classe Java pour montrer comment fonctionne la boucle for-each en Java
*/
classe publique ForEachTest {
public static void main(String args[]){
CustomCollection<String> myCollection = new CustomCollection<String>();
maCollection.add("Java");
maCollection.add("Scala");
maCollection.add("Groovy");
// Que fera ce code, langage d'impression, émission d'une exception ou erreur de compilation
pour (Langue de chaîne : maCollection){
System.out.println(langue);
}
}
}
Vous trouverez ci-dessous notre classe CustomCollection, qui est une classe générique qui, comme toute autre classe Collection, s'appuie sur une ArrayList et fournit des méthodes pour ajouter et supprimer des éléments de la collection.
Copiez le code comme suit :
test de paquet ;
classe publique CustomCollection<T>{
compartiment ArrayList<T> privé ;
public CustomCollection(){
seau = new ArrayList();
}
public int taille() {
return bucket.size();
}
public booléen isEmpty() {
return bucket.isEmpty();
}
public booléen contient(T o) {
return bucket.contains(o);
}
public boolean add(T e) {
return bucket.add(e);
}
public booléen supprimer (T o) {
return bucket.remove(o);
}
}
Répondre:
Le code ci-dessus ne sera pas compilé car notre classe CustomCollection n'implémente pas l'interface java.lang.Iterable. L'erreur de compilation est la suivante :
Copiez le code comme suit :
Exception dans le thread "main" java.lang.RuntimeException : code source non compilable - pour chaque non applicable au type d'expression
obligatoire : tableau ou java.lang.Iterable
trouvé : test.CustomCollection
à test.ForEachTest.main(ForEachTest.java:24)
Un fait intéressant à retenir est que la boucle for-each s'applique uniquement aux classes Java array et Collection qui implémentent l'interface Iterable, et puisque toutes les classes Collection intégrées implémentent l'interface java.util.Collection et ont hérité d'Iterable, cela Un détail souvent négligé peut être vu dans la déclaration de type de l'interface Collection "public interface Collection extends Iterable". Ainsi, afin de résoudre le problème ci-dessus, vous pouvez choisir de simplement laisser CustomCollection implémenter l'interface Collection ou d'hériter de AbstractCollection, qui est l'implémentation universelle par défaut et montre comment utiliser les classes abstraites et les interfaces en même temps pour une meilleure flexibilité. Examinons maintenant la deuxième énigme de la boucle for-each :
La deuxième difficulté avec les boucles Java for-each :
L’exemple de code suivant lèvera une ConcurrentModificationException. Ici, nous utilisons un itérateur standard et une boucle for-each pour parcourir ArrayList, puis supprimer les éléments. Vous devez savoir quel morceau de code lancera ConcurrentModificationException et pourquoi ? Notez que la réponse peut être les deux, ni l’un ni l’autre, ou l’une ou l’autre.
Copiez le code comme suit :
test de paquet ;
importer java.util.ArrayList ;
importer java.util.Collection ;
importer java.util.Iterator ;
/**
* Classe Java pour démontrer le fonctionnement interne de la boucle for-each en Java
* @auteur Javin Paul
**/
classe publique ForEachTest2 {
public static void main(String args[]){
Collection<String> list = new ArrayList<String>();
list.add("Android");
list.add("iPhone");
list.add("Windows Mobile");
// Quel code lancera ConcurrentModificationException, les deux,
// aucun ou l'un d'entre eux
// exemple 1
Itérateur<String> itr = list.iterator();
while(itr.hasNext()){
Chaîne lang = itr.next();
list.remove(lang);
}
//exemple 2
pour (Langage des chaînes : liste) {
list.remove(langue);
}
}
}
Environ 70 % des développeurs Java diront que le premier bloc de code lèvera une exception ConcurrentModificationException car nous n'utilisons pas la méthode Remove de l'itérateur pour supprimer des éléments, mais utilisons la méthode Remove() d'ArrayList. Cependant, peu de développeurs Java diraient que le même problème se produit avec la boucle for-each car nous n'utilisons pas d'itérateur ici. En fait, le deuxième extrait de code lève également une ConcurrentModificationException, qui devient évidente après avoir résolu la première confusion. Étant donné que la boucle for-each utilise un itérateur en interne pour parcourir la collection, elle appelle également Iterator.next(), qui vérifie les modifications (des éléments) et lève une ConcurrentModificationException. Vous pouvez le voir dans le résultat ci-dessous, que vous obtenez lorsque vous exécutez le deuxième extrait après avoir commenté le premier extrait.
Copiez le code comme suit :
Exception dans le thread "main" java.util.ConcurrentModificationException
sur java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
sur java.util.AbstractList$Itr.next(AbstractList.java:343)
à test.ForEachTest2.main(ForEachTest2.java:34)
Tout tourne autour de la boucle Java5 for-each. Nous avons constaté de nombreux problèmes rencontrés par les programmeurs Java lorsqu'ils écrivent du code pour parcourir une classe Collection, en particulier lorsqu'ils parcourent une collection tout en supprimant des éléments en même temps. N'oubliez pas de toujours utiliser la méthode delete de l'itérateur lorsque vous supprimez des objets d'une collection (comme une carte, un ensemble ou une liste). N'oubliez pas non plus que la boucle for-each n'est qu'un sucre syntaxique (sucre syntaxique) en plus de l'utilisation standard du). code itérateur standard sucre) uniquement.
Note du traducteur : Le sucre syntaxique, également traduit par grammaire enrobée de sucre, est un terme inventé par l'informaticien britannique Peter J. Landin, qui fait référence à un certain type de grammaire ajoutée aux langages informatiques. La syntaxe n'a aucun impact sur la fonctionnalité du langage informatique. langage, mais le rend plus facile à utiliser pour les programmeurs. De manière générale, l'utilisation de sucre de syntaxe peut augmenter la lisibilité du programme, réduisant ainsi le risque d'erreurs de code de programme.