なぜ、追加および削除の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();
}
}