`

List 迭代过程中删除或添加元素

阅读更多
1. List 迭代过程中删除元素采用list.remove(obj)会造成其size自减,modCount自增而产生问题:

Collection list = new ArrayList();
list.add("creek");
list.add("misty");
list.add("forest");

Iterator iter = list.iterator();

while (iter.hasNext()) {
    Object obj = iter.next();
    if ("creek".equals(obj))
       list.remove(obj);
}


运行时会报java.util.ConcurrentModificationException错误。

我们先看看java.util.ArrayList的相关代码:

private void fastRemove(int index) {
	modCount++;
	int numMoved = size - index - 1;
	if (numMoved > 0)
		System.arraycopy(elementData, index+1, elementData, index,
						 numMoved);
	elementData[--size] = null; // Let gc do its work
}


还有java.util.AbstractList的:

int expectedModCount = modCount;

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

public E next() {
		checkForComodification();
	try {
	E next = get(cursor);
	lastRet = cursor++;
	return next;
	} catch (IndexOutOfBoundsException e) {
	checkForComodification();
	throw new NoSuchElementException();
	}
}

final void checkForComodification() {
	if (modCount != expectedModCount)
	throw new ConcurrentModificationException();
}


当调用iterator()方法的时候,expectedModCount = modCount (等于3,三次添加元素)
第一次循环的时候,把第一个元素给删除了,这时modCount++ (等于4)
第二次调用iter.next()会调用checkForComodification()方法,check到这两个值不相等,所以报异常。

如果我们需要在迭代的过程中对元素进行删除操作,使用AbstractList提供的remove()方法,当然这也不是线程安全的:

	public void remove() {
	    if (lastRet == -1)
		throw new IllegalStateException();
            checkForComodification();

	    try {
		AbstractList.this.remove(lastRet);
		if (lastRet < cursor)
		    cursor--;
		lastRet = -1;
		// Let the values of the two variables be equal
		// so that the check would be passed
		expectedModCount = modCount;
	    } catch (IndexOutOfBoundsException e) {
		throw new ConcurrentModificationException();
	    }
	}


可以看到这里的expectedModCount已经设置成和modCount相等了。

另一种方式是利用并发库里的CopyOnWriteArrayList类:
Collection list = new CopyOnWriteArrayList();
...


2. List 迭代过程中添加元素采用list.add(obj)会造成其size自增,modCount自增而产生问题,这里就不再赘述。
分享到:
评论

相关推荐

    Iterator遍历过程中list删除导致异常

    当你想在迭代过程中删除元素时,应该使用`Iterator`的`remove()`方法,而不是直接调用集合的`remove()`方法。这样,`Iterator`会正确处理集合的内部状态,避免异常: ```java List&lt;String&gt; list = new ArrayList...

    STL中list的使用

    4. **push_back和push_front方法**:分别在`list`的末尾和开头添加元素。 5. **remove和remove_if方法**:用于删除满足条件的元素。如`c1.remove(10);` 删除所有值为10的元素。 6. **reverse方法**:反转`list`中的...

    内置迭代器的linked list例题

    值得注意的是,迭代器提供了`remove()`方法,允许在遍历过程中安全地删除元素。如果在调用`remove()`之前没有调用`next()`,或者在没有更多元素的情况下调用`remove()`,那么会抛出`NoSuchElementException`。此外,...

    SafeList:一个在迭代时处理添加和删除元素的列表

    在当前循环位置之后添加元素时,循环将继续进行处理,就好像它们从一开始就存在一样。 当前循环位置之前添加的元素将被跳过。 在当前循环位置之前删除的元素不会对循环产生影响。 在当前循环位置之后删除的元素将...

    java使用ListIterator对List遍历时添加修改删除​

    在Java编程中,`ListIterator`是`List`接口提供的一种特殊的迭代器,它具有双向遍历的能力,不仅可以向前遍历列表,还可以向后遍历。`ListIterator`还提供了在遍历过程中添加、修改和删除元素的功能,使得对列表的...

    【IT十八掌徐培成】Java基础第10天-04.List-迭代器-对象等价性.zip

    // 如果在迭代过程中需要删除元素,应使用iterator.remove(),而非list.remove() if ("Element1".equals(element)) { iterator.remove(); } } ``` 上述代码展示了如何使用迭代器遍历并可能删除List中的元素。...

    设计模式之迭代器模式

    1. **迭代器(Iterator)**:迭代器接口,定义了遍历元素的方法,如`hasNext()`用于检查是否还有更多元素,`next()`用于获取下一个元素,以及可能存在的`remove()`方法用于删除当前元素。 2. **聚合对象(Colllection)*...

    java Iterator迭代器的使用

    Java中的`Iterator`接口是Java... 可能这个图片文件是用来辅助理解`Iterator`概念的,比如它可能包含了一个迭代过程的流程图或示例代码的截图。在实际学习中,视觉辅助材料可以帮助我们更好地理解和记忆复杂的概念。

    [C++][经验总结]vectory迭代器(iterator)失效

    4. **避免在循环中插入或删除元素**:尽可能地将插入和删除操作移到循环之外,或者使用其他容器,如`list`,其迭代器在插入和删除时不会失效。 在给定的测试用例"InvalidIteratorTest"中,可能包含了模拟这些情况的...

    C++中list用法

    - `erase()`:删除list中的一个或多个元素。 - `remove()`:根据给定值从list中移除所有匹配项。 - `remove_if()`:根据给定的条件从list中移除所有匹配项。 - `resize()`:改变list的大小。 - `swap()`:交换...

    forEach中为什么不能删除元素解决方案.pdf

    然而,在使用`forEach`循环时,直接尝试修改遍历的集合(例如删除或添加元素)是不被允许的,因为这会导致`ConcurrentModificationException`异常。本文将探讨在使用`forEach`循环中遇到无法删除元素的问题,并提供...

    java迭代器模式实现正反向遍历

    在示例代码中,`ConcreteAggregate`类使用`List`作为数据存储,提供了添加元素、获取元素数量以及根据索引获取元素的能力。 #### 4. 具体迭代器(ConcreteIterator) 具体迭代器实现了迭代器接口,并与具体的聚合...

    java LinkedList的添加删除操作

    在Java编程语言中,LinkedList是一种线性数据结构,属于集合框架的一部分,实现了List接口和Deque接口。LinkedList以链表的形式存储元素,这使得它在添加和删除元素时具有较高的效率,尤其是在列表的中间或开头进行...

    C#设计模式迭代器示例

    添加、删除元素的方法 public IEnumerator&lt;int&gt; GetEnumerator() { return items.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } ``` 2. **实现迭代器**:...

    迭代器的用法

    在迭代器遍历过程中,对集合进行修改(如添加或删除元素)可能会影响迭代器的行为。例如,如果在调用`next()`之后调用`remove()`,则通常不会有问题。但是,在调用`hasNext()`或`next()`之前删除元素可能会导致...

    Java学习之Iterator(迭代器)的一般用法

    迭代器提供了一个`remove()`方法,允许在遍历过程中删除当前元素。需要注意的是,调用`remove()`方法前必须先调用过一次`next()`方法,否则会抛出`IllegalStateException`异常。例如: ```java while (iterator....

    Headfirst(九)迭代器模式

    4. 创建具体聚合类,实现抽象聚合类的方法,包括存储元素、添加元素、删除元素等,并实现`createIterator()`方法,返回具体的迭代器实例。 5. 在客户端代码中,通过调用聚合对象的`createIterator()`方法获取迭代器...

    java基础 集合-22-迭代器设计模式

    - 如果在迭代过程中添加或删除元素,建议使用`Iterator`的`remove()`方法,而不是集合的`add()`或`remove()`方法,以避免并发修改异常。 总结来说,Java中的迭代器设计模式是集合操作的重要组成部分,它允许程序员...

    Java 实例 - List 循环移动元素源代码+详细指导教程.zip

    学习这个教程,你将掌握Java List接口的基础知识,包括如何创建List、添加元素、遍历列表以及如何在遍历过程中安全地移动元素。这将有助于你在实际项目中更有效地处理数据结构和算法问题。同时,提供的源代码实例将...

Global site tag (gtag.js) - Google Analytics