ArrayListのシリーズ--ArrayListなぜ追加および削除のforeachのセットを使用していませんか?

なぜ、追加および削除のforeachのArrayListのコレクションを使用していませんか?

はじめに:foreachのシンタックスシュガー

使用して、実際の内部イテレータイテレータ方法をforeachの糖衣構文を使用してArrayListを

List<String> list = new ArrayList<String>(10);
list.add("1");
list.add("2");
//方式1
for (String str : list) {
   
    ....
}

//方式二
for (Iterator i=list.iterator(); i.hasNext(); ) {
    String str = i.next();
}
    
//实现了Iterable接口的类采用iterator生成迭代器 所有Collection集合类都实现了该接口
/**Returns an iterator over the elements in this list in proper sequence.
 *The returned iterator is fail-fast.
 **/
 public Iterator<E> iterator() {
        return new Itr();
    }

導入foreachの具体的なシンタックスシュガー:参照朱の僕のブログのhttps://blog.csdn.net/u013256816/article/details/50736498

そして、前記配列が異なるコレクションです

テキスト:エラーでforeachの追加と削除

次のコードを考えてみましょう

List<String> arrayList1 = new ArrayList<String>();
arrayList1.add("1");
arrayList1.add("2");
for (String s : arrayList1) {
 if("1".equals(s)){
  //不报错
 arrayList1.remove(s);
 }
}
List<String> arrayList2 = new ArrayList<String>();
arrayList2.add("2");
arrayList2.add("1");
for (String s : arrayList2) {
 if("1".equals(s)){
  //导致报错
 arrayList2.remove(s);
 }
}

次のように異常な情報があります

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)

ArrayListにクラスのITRソースを見てみましょう

 private class Itr implements Iterator<E> {
        /**
         * Index of element to be returned by subsequent call to next.
         * 翻译为游标,下标。认为指针更为准确,指当前数组访问的位置
         * (学过数据库的话应该对游标有点熟悉)
         */
        int cursor = 0;

        /**
         * Index of element returned by most recent call to next or
         * previous.  Reset to -1 if this element is deleted by a call
         * to remove.
         * 最近访问节点的前一个下标 如果调用了remove则重置为-1
         */
        int lastRet = -1;

        /**
         * The modCount value that the iterator believes that the backing
         * List should have.  If this expectation is violated, the iterator
         * has detected concurrent modification.
         * 期望的修改数量 初始值modcount 如果不等于 抛出异常
         */
        int expectedModCount = modCount;

       //如果当前游标不等于size大小,则存在下一个元素
        public boolean hasNext() {
            return cursor != size();
        }

       //遍历下一个元素
        public E next() {
            //检测并发修改
            checkForComodification();
            try {
                int i = cursor;
                E next = get(i);
                lastRet = i;
                //游标加一
                cursor = i + 1;
                //从第0个开始遍历
                return next;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                //调用list的remove方法
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                lastRet = -1;
                //同步modCount值
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                //抛出异常的位置
                throw new ConcurrentModificationException();
        }
    }

この方法は、ArrayListのを取り除くと同時に掲載しました

 public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
               //如果元素为空,删除第一个为null的值
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                //删除第一个元素相等的值
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

   private void fastRemove(int index) {
       //修改数量加一
       //数组新增删除modCount都会增加
        modCount++;
       //需要移动的数据下标
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //调用本地方法进行数组copy
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //帮助GC 如果数组该元素无法访问,但一直有值,导致无法GC,可能有隐患
        //同时size减一
        elementData[--size] = null; // clear to let GC do its work
    }

出典:我々はコードを解析する前に

List<String> arrayList1 = new ArrayList<String>();
arrayList1.add("1");
arrayList1.add("2");
for (String s : arrayList1) {
 if("1".equals(s)){
  //不报错
 arrayList1.remove(s);
 }
    //System.out.println(S);  实际上只会打印1
}
List<String> arrayList2 = new ArrayList<String>();
arrayList2.add("2");
arrayList2.add("1");
for (String s : arrayList2) { //第三次循环报错位置
 if("1".equals(s)){
  //导致报错的原因
 arrayList2.remove(s);
 }
}

arrayList1トラバーサルは、最初のパスがItr.next()メソッドは、カーソル= 0 +1に入ると、リア( "1")、第二パス中アレイサイズ-1 = 1、、コンパレータカーソルを削除!=サイズ()は偽であり、それはループの外で、実際に第二の要素にトラバースされていません。

arrayList2が横断するとき、最初のトラバース、カーソル= 1の後、第二のパス、カーソル= 2を入力し、同時に、第3のパスに、その配列の大きさを1に低減され、比較をmodCount加えたものを第二の要素を削除しますカーソル!=サイズ()はtrueです。Itr.next()メソッドに。modCount = 3、expectedModCount = 2、異常が報告されました。

概要:DOはArrayListのforeachの中の要素の追加や削除をしません

foreachの要素が早送りのためのIteratorオブジェクトに入れて、削除するイテレータオブジェクトを使用する必要があり、削除要素を横断する必要があります。このように、以下のものを使用することが可能です。

Iterator<String> iterator = arrayList2.iterator();
while (iterator.hasNext()) {
	String item = iterator.next();
	if ("1".equals(item)) {
		iterator.remove();
	}
}
出版元の記事 ウォンの賞賛0 ビュー115

おすすめ

転載: blog.csdn.net/sinat_22143835/article/details/104017319