import java.util.*;
public class object {
public static void main(String[] args) {
String str1 = new String("abcde");
String str2 = new String("abcde");
String str3 = new String("abcde");
String str4 = new String("abcde");
String str5 = new String("abcde");
List list = new ArrayList();
list.add(str1);
list.add(str2);
list.add(str3);
list.add(str4);
list.add(str5);
System.out.println("list.size()=" + list.size());
for (int i = 0; i < list.size(); i++) {
if (((String) list.get(i)).startsWith("abcde")) {
list.remove(i);
}
}
System.out.println("after remove:list.size()=" + list.size());
}
}
运行结果不是:
list.size()=5
after remove:list.size()=0
居然是:
list.size()=5
after remove:list.size()=2
原因:List每remove掉一个元素以后,后面的元素都会向前移动,此时如果执行i=i+1,则刚刚移过来的元素没有被读取。
解决方法:
1.倒过来遍历list
for (int i = list.size()-1; i > =0; i--) {
if (((String) list.get(i)).startsWith("abcde")) {
list.remove(i);
}
}
2.每移除一个元素以后再把i移回来
for (int i = 0; i < list.size(); i++) {
if (((String) list.get(i)).startsWith("abcde")) {
list.remove(i);
i=i-1;
}
}
3.使用iterator.remove()方法删除
for (Iterator it = list.iterator(); it.hasNext();) {
String str = (String)it.next();
if (str.equals("chengang")){
it.remove();
}
}
注意:在遍历list或者说在遍历集合过程中,执行了删除动作就会报错
工作中碰到个ConcurrentModificationException。代码如下:
List list = ...;
for(Iterator iter = list.iterator(); iter.hasNext();) {
Object obj = iter.next();
...
if(***) {
list.remove(obj);
}
}
在执行了remove方法之后,再去执行循环,iter.next()的时候,报java.util.ConcurrentModificationException(当然,如果remove的是最后一条,就不会再去执行next()操作了)
下面来看一下源码
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
public interface Collection<E> extends Iterable<E> {
...
Iterator<E> iterator();
boolean add(E o);
boolean remove(Object o);
...
}
这里有两个remove方法
接下来来看看AbstractList
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
//AbstractCollection和List都继承了Collection
protected transient int modCount = 0;
private class Itr implements Iterator<E> { //内部类Itr
int cursor = 0;
int lastRet = -1;
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();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet); //执行remove对象的操作
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount; //重新设置了expectedModCount的值,避免了ConcurrentModificationException的产生
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount) //当expectedModCount和modCount不相等时,就抛出ConcurrentModificationException
throw new ConcurrentModificationException();
}
}
}
remove(Object o)在ArrayList中实现如下:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
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
....
}
所以,产生ConcurrentModificationException的原因就是:
执行remove(Object o)方法之后,modCount和expectedModCount不相等了。然后当代码执行到next()方法时,判断了checkForComodification(),发现两个数值不等,就抛出了该Exception。
要避免这个Exception,就应该使用remove()方法。
这里我们就不看add(Object o)方法了,也是同样的原因,但没有对应的add()方法。一般嘛,就另建一个List了
下面是网上的其他解释,更能从本质上解释原因:
Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
分享到:
相关推荐
总结一下,使用 `list` 的 `remove()` 方法删除结构体成员(对象实例)的关键在于找到要删除的元素,并根据其唯一的标识进行匹配。在实际编程中,我们还需要考虑到异常处理和对原列表的影响,以及选择合适的删除策略...
这篇文章主要讲解了`list`中的两个重要成员函数`erase`和`remove`,它们用于删除链表中的元素。理解这两个函数的正确用法对于编写高效且无误的C++代码至关重要。 首先,`erase`函数的主要作用是删除链表中特定位置...
`remove()`方法是`List`接口中的一个关键操作,用于从列表中删除指定的元素或根据索引移除元素。在使用`remove()`方法时,需要注意一些重要的细节以避免潜在的问题和错误。下面将详细介绍`List.remove()`方法的两种...
在标准模板库(STL)中,`list`容器是一个双向链表,它提供了高效的插入和删除操作,尤其是在列表的头部或尾部进行操作时,性能尤为突出。下面将详细介绍`list`的各种功能和用法。 ### 创建和初始化 1. **空list**...
使用RemoveDrive要注意的是,尽管它能快速卸载设备,但并不意味着数据安全就得到了保障。在执行卸载命令前,应确保没有正在进行的读写操作,否则可能会导致数据丢失。此外,对于不熟悉命令行操作的用户,建议在了解...
需要注意的是,Robot Framework中的列表用`@{list}`表示,而Python中用`$list`。比较两个`@{list}`时,直接写成`$list`。例如,`Lists Should Be Equal ${list} ${list1}` 判断两个列表是否相同。 8. **Remove From...
当我们需要遍历List并根据条件删除特定元素时,需要注意正确的方法,以避免在遍历过程中出现错误。以下将详细介绍如何在C#中遍历List并删除元素,包括正序和倒序遍历的技巧。 首先,我们来看一下错误的遍历方式。...
在`ListBox`中,如果你要根据对象的字符串表示来查找并移除元素,可以遍历`Items`集合,将每个元素转换为字符串,然后与目标字符串比较。如果匹配,则调用`Remove`方法移除该元素。这种方法适用于元素是自定义类且...
`insert()`函数允许我们在列表中的任意位置插入一个新元素,而`remove()`函数则用于移除列表中的指定元素。 ##### `insert(index, obj)` - **功能**:将对象`obj`插入到列表的`index`位置。注意这里的`index`是基于...
C# List是.NET Framework...需要注意的是,虽然List提供了强大的功能,但是性能问题仍然是开发者需要注意的地方,尤其是当处理大量数据且数据类型为值类型时。合理选择数据结构和方法,可以有效避免不必要的性能开销。
需要注意的是,在选择使用IList还是ArrayList类时,需要考虑性能和类型安全性问题。如果使用IList,那么在大多数情况下执行速度更快、更加类型安全,但如果使用值类型,则需要考虑装箱和取消装箱问题。
### 两个List比较取不同的对象 在Java编程中,经常需要对两个`List`进行比较,...最后,正确使用迭代器可以在遍历过程中避免并发修改异常等问题。在实际应用中,可以根据具体需求灵活调整这些技术点,以达到最佳效果。
aList.Remove("a"); 结果为 bcde。 2. public virtual void RemoveAt(int index):移除 ArrayList 的指定索引处的元素。 例如:ArrayList aList = new ArrayList(); aList.Add("a"); aList.Add("b"); aList.Add("c...
如果在多线程环境中操作集合,需要注意线程安全问题,可能需要使用`CopyOnWriteArrayList`或其他同步容器,或者对比较过程进行同步控制。 通过理解并熟练运用这些方法,我们可以有效地比较和操作两个List集合,...
在C#编程中,列表(List)是一种常用的集合类,用于存储一组同类型的元素。当需要对列表中的元素进行随机排序时,可以采用多种方法。这里我们重点介绍一种基于`Random`类的方法,如标题和描述中所述。这种方法通过创建...
在Java编程语言中,`List`接口是集合框架的重要组成部分,它提供了有序元素集合的实现,并允许重复元素的存在。本文将详细解释`List`接口中的常用方法,帮助开发者更好地理解和运用这些功能强大的工具。 #### 1. ...
当在循环中使用`list.remove()`时,需要注意列表的长度会在每次调用该方法时减少1。这会导致循环的索引失效或跳过某些元素。例如: ```python dat = ['1', '2', '3', '0', '0', '0'] for item in dat: if item == ...
在实际编码中,我们还应注意异常处理、集合操作的效率优化以及在多线程环境下对List的同步控制。此外,List接口提供的其他方法,如`list.indexOf()`, `list.subList()`, `list.sort()`, `list.containsAll()`等,都...
### C# 中 Array、ArrayList 和 List 的区别 在C#编程语言中,处理集合数据时,程序员经常需要根据实际需求选择合适的集合类型。本文将详细解释C#中Array、ArrayList和List之间的区别,并通过示例代码帮助理解这些...
Python提供了remove()方法用于从list中删除指定元素,但需要注意处理可能的“商品不存在”异常。 4. **商品的清空**:清空购物车就是将整个list置为空。这可以通过重新赋值实现,如`cart = []`。 5. **cookie技术*...