Maison  >  Questions et réponses  >  le corps du texte

为什么java不要在foreach循环里进行元素的remove/add操作


选自《阿里巴巴JAVA开发手册》

图1代码执行情况是:解释删除1这个元素不会报错,但是删除2这个元素报错了,这个情况如何解释?

PHPzPHPz2716 Il y a quelques jours1134

répondre à tous(8)je répondrai

  • 大家讲道理

    大家讲道理2017-04-18 10:56:42

    La source de l'erreur checkForComodification() peut être connue grâce à l'erreur signalée. Si vous souhaitez éviter les erreurs, vous devez conserver modCount != expectedModCount comme false .
    list.remove(Object) appellera la méthode fastRemove(int), et elle modifiera inévitablement modCount à ce moment-là, et une erreur se produira à ce moment-là.
    Iterator<String> iterator = list.iterator() ; L'implémentation de cette méthode consiste à renvoyer une classe interne Itr (cette classe est utilisée dans le processus d'itération), mais la raison pour laquelle cela iterator.remove() ne provoque pas d'erreurs est due à la relation entre cette méthode et L'implémentation consiste à vérifier ArrayList.this.remove avant de faire le checkForComodfication réel et à faire remove après expectedModCount = modCount afin qu'aucune erreur ne se produise.

    Itr.removeMise en œuvre

    public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();
    
                try {
                    ArrayList.this.remove(lastRet);
                    cursor = lastRet;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }

    S'il y a quelque chose qui ne va pas, veuillez le signaler @ChaCha哥 @puliuyinyi

    répondre
    0
  • PHP中文网

    PHP中文网2017-04-18 10:56:42

    Dans le cas d'un seul thread, lors de la suppression d'éléments lors du parcours de la liste, vous devez utiliser la méthode Remove d'Iterator au lieu de la méthode Remove de List, sinon une ConcurrentModificationException se produira. Imaginez simplement si un enseignant compte le nombre d'élèves dans toute la classe, et si les élèves ne respectent pas les règles et ne sortent pas et n'entrent pas, l'enseignant ne pourra certainement pas les compter.

    Dans le cas du multi-threading, référez-vous à un de mes blogs : http://xxgblog.com/2016/04/02...

    répondre
    0
  • 天蓬老师

    天蓬老师2017-04-18 10:56:42

    Tout d'abord, cela implique des opérations multi-thread. Iterator ne prend pas en charge les opérations multi-thread. La classe List maintiendra une variable modCount en interne pour enregistrer le nombre de modifications
    Exemple : code source ArrayList

    protected transient int modCount = 0;

    Chaque fois qu'un Iterator est généré, l'Iterator enregistrera le modCount. Chaque fois que la méthode next() est appelée, l'enregistrement sera comparé au modCount de la classe externe List. S'il s'avère inégal, un. une exception d'édition multithread sera levée.

    Pourquoi fais-tu ça ? Je crois comprendre que vous avez créé un itérateur étroitement couplé au contenu de la collection à parcourir, ce qui signifie que le contenu de la collection correspondant à cet itérateur est le contenu actuel. Je ne veux absolument pas le faire dans mon cas. tri à bulles. Quand , il y a encore des threads qui insèrent des données dans ma collection, n'est-ce pas ? Java utilise donc ce mécanisme de traitement simple pour empêcher la collection d'être modifiée pendant le parcours.

    Quant à savoir pourquoi supprimer "1" est suffisant, la raison réside dans la méthode hasNext() de foreach et de l'itérateur. Le sucre syntaxique de foreach est en fait

    .
    while(itr.hasNext()){
        itr.next()
    }

    Donc, chaque boucle exécutera hasNext() en premier, alors jetez un œil à la façon dont hasNext() d'ArrayList est écrit :

    public boolean hasNext() {
        return cursor != size;
    }

    cursor est une variable utilisée pour marquer la position de l'itérateur. La variable commence à 0 et effectue une opération +1 à chaque fois que next est appelé, donc :
    Après que votre code supprime "1", size=1, curseur = 1, à ce moment hasNext() renvoie false et termine la boucle, donc votre itérateur n'appelle pas next pour trouver le deuxième élément, donc il n'y a aucun moyen de détecter modCount, donc il n'y aura pas d'exception de modification multi-thread
    mais lorsque vous avez supprimé "2", l'itérateur a appelé next deux fois, à ce moment-là, size=1, curseur=2 et hasNext() a renvoyé true, donc l'itérateur a bêtement appelé next() à nouveau, ce qui a également déclenché If. modCount n'est pas égal, une exception de modification multithread sera levée.

    Lorsque votre ensemble comporte trois éléments, vous constaterez comme par magie que la suppression de "1" lèvera une exception, mais la suppression de "2" ne posera pas de problème. La raison est liée à l'exécution du programme ci-dessus. L'ordre est cohérent. .

    répondre
    0
  • 黄舟

    黄舟2017-04-18 10:56:42

    Étant donné que le nombre dans la collection change lorsque vous ajoutez ou supprimez des éléments, des problèmes peuvent survenir lors du parcours. Par exemple, si une collection contient 10 éléments, elle doit être parcourue 10 fois. le nombre de traversées est incorrect, donc une erreur sera signalée

    répondre
    0
  • PHPz

    PHPz2017-04-18 10:56:42

    Supprimez-les simplement dans l’ordre inverse. Quoi qu’il en soit, essayez de ne pas supprimer la liste. Vous pouvez ajouter une balise de suppression

    répondre
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-18 10:56:42

    La description jaune dans le document est très intéressante.

    Le résultat de l'exécution de cet exemple dépassera les attentes de tout le monde. Essayez donc de remplacer « 1 » par « 2 », cela aura-t-il le même résultat ?

    Vous devez quand même regarder le code source de ArrayList pour cela, vous le saurez d'un coup d'œil.

    répondre
    0
  • 巴扎黑

    巴扎黑2017-04-18 10:56:42

    Supprimez-le simplement dans l'ordre inverse

    répondre
    0
  • PHP中文网

    PHP中文网2017-04-18 10:56:42

    ArrayList n'est pas thread-safe, ce qui signifie que vous modifiez la liste pendant le parcours.
    ArrayList lèvera une exception de modification simultanée dans ce cas.

    répondre
    0
  • Annulerrépondre