Maison  >  Article  >  Java  >  Comment supprimer des éléments lors du parcours d'une liste ou d'une carte en Java

Comment supprimer des éléments lors du parcours d'une liste ou d'une carte en Java

高洛峰
高洛峰original
2017-01-22 16:25:461880parcourir

Il existe de nombreuses façons de parcourir et de supprimer des éléments dans une liste ou une carte, et des problèmes surviendront en cas d'utilisation incorrecte. Apprenons-en davantage à travers cet article.

1. Supprimer des éléments lors du parcours de la liste

Utiliser le parcours d'indice d'index

Exemple : supprimer 2 dans la liste

public static void main(String[] args) {
  List<Integer> list = new ArrayList<Integer>();
  list.add(1);
  list.add(2);
  list.add(2);
  list.add(3);
  list.add(4);
   
  for (int i = 0; i < list.size(); i++) {
   if(2 == list.get(i)){
    list.remove(i);
   }
   System.out.println(list.get(i));
  }
   
  System.out.println("list=" + list.toString());
   
 }

Résultat de sortie :

1
2
3
4
list=[1, 2, 3, 4]

Problème :

Le résultat montre qu'un seul 2 a été supprimé et les 2 autres ont été omis, pourquoi Oui : après la suppression des 2 premiers, le nombre d'éléments de l'ensemble est réduit de 1 et les éléments suivants sont avancés de 1, entraînant l'omission des 2 seconds.

Pour le parcours de boucle

Exemple :

public static void listIterator2(){
  List<Integer> list = new ArrayList<Integer>();
  list.add(1);
  list.add(2);
  list.add(2);
  list.add(3);
  list.add(4);
   
  for (int value : list) {
   if(2 == value){
    list.remove(value);
   }
   System.out.println(value);
  }
   
  System.out.println("list=" + list.toString());
   
 }


Résultat :

Exception in thread "main" 1
2
java.util.ConcurrentModificationException
 at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
 at java.util.ArrayList$Itr.next(Unknown Source)
 at test.ListIterator.listIterator2(ListIterator.java:39)
 at test.ListIterator.main(ListIterator.java:10)

Explication :

Description de ConcurrentModificationException dans jdk :

classe publique ConcurrentModificationException extends

RuntimeException Cette exception est lancé lorsque la méthode détecte une modification simultanée de l'objet, mais n'autorise pas une telle modification.

Par exemple, lorsqu'un thread parcourt une collection, un autre thread n'est généralement pas autorisé à modifier linéairement la collection. Souvent, dans ces cas, le résultat de l’itération est indéterminé. Certaines implémentations d'itérateurs (y compris toutes les implémentations de collections génériques fournies par le JRE) peuvent choisir de lever cette exception si ce comportement est détecté. Les itérateurs qui effectuent cette opération sont appelés itérateurs à échec rapide, car l'itérateur échoue complètement rapidement sans risquer un comportement arbitraire non spécifié à un moment donné dans le futur.

Remarque : Cette exception n'indiquera pas toujours que l'objet a été modifié simultanément par différents threads. Un objet peut lever cette exception si un seul thread émet une séquence d'appels de méthode qui viole le contrat de l'objet. Par exemple, si un thread modifie directement une collection tout en la parcourant à l'aide d'un itérateur à échec rapide, l'itérateur lèvera cette exception.

Remarque : le comportement rapide des itérateurs n'est pas garanti car, en général, il n'est pas possible de garantir de manière concrète si des modifications simultanées non synchronisées se produiront. Les opérations rapides en cas d'échec génèrent une ConcurrentModificationException au mieux. Par conséquent, c'est une erreur d'écrire un programme qui s'appuie sur cette exception pour améliorer l'exactitude de telles opérations. L'approche correcte est la suivante : ConcurrentModificationException ne doit être utilisée que pour détecter les bogues.

Pour chacun, Java utilise en fait un itérateur pour le traitement. L'itérateur ne permet pas la suppression de la collection lors de l'utilisation de l'itérateur. Cela a donc amené l’itérateur à lancer ConcurrentModificationException.

Voie correcte

Exemple :

public static void listIterator3(){
  List<Integer> list = new ArrayList<Integer>();
  list.add(1);
  list.add(2);
  list.add(2);
  list.add(3);
  list.add(4);
   
  Iterator<Integer> it = list.iterator();
  while (it.hasNext()){
   Integer value = it.next();
   if (2 == value) {
    it.remove();
   }
    
   System.out.println(value);
  }
   
  System.out.println("list=" + list.toString());
 }

Résultat :

1
2
2
3
4
list=[1, 3, 4]

2. Suppression d'éléments lors du parcours de la carte

Exemple d'approche correcte :

public static void main(String[] args) {
 HashMap<String, String> map = new HashMap<String, String>();
 map.put("1", "test1");
 map.put("2", "test2");
 map.put("3", "test3");
 map.put("4", "test4");
  
 //完整遍历Map
 for (Entry<String, String> entry : map.entrySet()) {
  System.out.printf("key: %s value:%s\r\n", entry.getKey(), entry.getValue());
 }
  
 //删除元素
 Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
 while(it.hasNext())
 {
  Map.Entry<String, String> entry= it.next();
  String key= entry.getKey();
  int k = Integer.parseInt(key);
  if(k%2==1)
  {
   System.out.printf("delete key:%s value:%s\r\n", key, entry.getValue());
   it.remove();
  }
 }
  
 //完整遍历Map
 for (Entry<String, String> entry : map.entrySet()) {
  System.out.printf("key: %s value:%s\r\n", entry.getKey(), entry.getValue());
 }
}


Résultat :

key: 1 value:test1
key: 2 value:test2
key: 3 value:test3
key: 4 value:test4
delete key:1 value:test1
delete key:3 value:test3
key: 2 value:test2
key: 4 value:test4

Remarque

Mais pour la méthode remove() de l'itérateur, il y a aussi des choses auxquelles nous devons prêter attention :

Chaque fois l'itérateur .next est appelée la méthode (), la méthode Remove() ne peut être appelée qu'une seule fois.

Avant d'appeler la méthode remove(), la méthode next() doit être appelée une fois.

Description de la méthode Remove() dans JDK-API :

void Remove() supprime le dernier élément renvoyé par l'itérateur de la collection pointée par l'itérateur (action facultative). Cette méthode ne peut être appelée qu'une seule fois par appel au suivant. Le comportement d'un itérateur n'est pas défini si la collection pointée par l'itérateur est modifiée alors qu'elle est itérée d'une manière autre qu'en appelant cette méthode.

Lance : UnsupportedOperationException - si l'itérateur ne prend pas en charge l'opération de suppression. IllegalStateException - si la méthode suivante n'a pas été appelée ou si la méthode Remove a été appelée depuis le dernier appel à la méthode suivante.

Résumé

Ce qui précède concerne la suppression d'éléments pendant le processus de parcours de List et Map. J'espère que le contenu de cet article pourra apporter de l'aide à l'étude ou au travail de chacun si vous en avez. questions Vous pouvez laisser des messages pour communiquer.

Pour plus d'articles sur la façon de supprimer des éléments lors du parcours d'une liste ou d'une carte en Java, veuillez faire attention au site Web PHP chinois !

Déclaration:
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