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自增而产生问题,这里就不再赘述。
分享到:
相关推荐
在当前循环位置之后添加元素时,循环将继续进行处理,就好像它们从一开始就存在一样。 当前循环位置之前添加的元素将被跳过。 在当前循环位置之前删除的元素不会对循环产生影响。 在当前循环位置之后删除的元素将...
* add(Object obj):向集合中添加元素 obj。 * clear():清空集合中的所有元素。 * contains(Object obj):判断集合中是否包含指定元素 obj。 * size():返回集合中元素的个数。 * isEmpty():判断集合中是否...
* add(E e):添加元素到集合中 * remove(Object o):从集合中删除元素 * contains(Object o):检查元素是否在集合中 * size():返回集合的大小 1.2.2 迭代器 迭代器是集合框架中的一个重要概念。它允许我们遍历...
3)把集合中的元素打印出来(使用迭代器Iterator) 2、编写程序练习List集合的基本使用: 1) 创建一个只能容纳String对象名为names的ArrayList集合; 2)按顺序往集合中添加5个字符串对象:"张三"、"李四"、"王五...
deque 通常在需要快速地在两端添加或移除元素,但又不想承受像 list 那样的额外开销时使用。 deque的主要特性: 双端操作:deque 允许在序列的前端和后端快速插入和删除元素。 内部引用:deque 通常不会将所有元素...
* addAll(Collection<? extends E> c):添加一个集合中的所有元素到当前集合中。 * remove(Object o):删除集合中的一个元素。 * removeAll(Collection<?> c):删除集合中的所有元素。 * clear():清空集合中的所有...
要添加元素: var myObjectReference = myList . add ( myObject ) ; // add on front by default// orvar myObjectReference = myList . addFront ( myObject ) ;// orvar myObjectReference = myList . addBack ...
没有规定增长政策的细节,除了添加元素具有不变的摊销时间成本。 应用程序可以添加大量使用ensureCapacity操作元件的前增大ArrayList实例的容量。 这可能会减少增量重新分配的数量。 请注意,此实现不同步。 ...
List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加、删除、设定元素,还能向前或向后遍历。 实现List接口的常用类有...
增长政策的细节无法超越的事实,添加元素具有恒定的摊余成本的时间规定。 应用程序可以添加大量使用的ensureCapacity操作元件的前增大ArrayList实例的容量。 这可以减少增量再分配的数量。 注意,此实现不是同步的...
通过使用 listIterator() 方法可以获取 List 集合的迭代器,然后使用 hasNext() 方法检查是否还有下一个元素,如果有,则使用 next() 方法获取该元素,并使用 equals() 方法检查是否等于"abc",如果等于,则使用 ...
a.begin()迭代器返回指向容器中第一个元素的迭代器;a.end()迭代器返回超尾值迭代器;a.size()UINT返回容器中的元素个数,等价于a.end() – a.begin();a.swap(b)void交换a和b的内容;a = = b可转换为BOOL如果a和b...
Collection 接口提供了基本的集合操作,如添加、删除、遍历等。 二、List 接口的特点 List 接口是 Collection 接口的子接口,它的特点是元素是有顺序的,可以重复的。List 接口提供了根据索引访问元素的方法,如 ...
ArrayList ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,...添加元素 访问元素 修改元素 删除元素 计算大小 迭代数组列表 其他的引用类型 ArrayList 排序 Java ArrayList 方法
} 其中,第 行部分在定义 List 时定义了泛型,保证 List 中的元素都是 Student 类型。因此在 第 行部分在取出 List 中的元素时就不需要再强制转换了。 另外,在前面的比较接口中也可以使用泛型,例如例 3.3 的 ...
返回一个迭代器,可以使用 list() 来转换为列表 8 dictname.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default 9 dictname.update(dict2) 把字典dict2的键/值对更新...
返回一个迭代器,可以使用 list() 来转换为列表 8 dictname.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default 9 dictname.update(dict2) 把字典dict2的键/值对更新...
返回一个迭代器,可以使用 list() 来转换为列表 8 dictname.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default 9 dictname.update(dict2) 把字典dict2的键/值对更新...
ArrayList 的默认大小为 10,添加元素时使用 ensureCapacityInternal() 方法来保证容量足够,如果不够时,需要使用 grow() 方法进行扩容,新容量的大小为 oldCapacity + (oldCapacity >> 1) ,也就是旧容量的 1.5 倍...