本文已参与「新人创作礼」活动,一起开启掘金创作之路。
问题的引出
当我们从集合中找出某个元素并删除的时候可能出现一种并发修改异常问题。
一、哪些问题遍历存在问题?
迭代器遍历过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改至不一致。
例如:
List<String> list=new ArrayList<>();
list.add("罗兆1");
list.add("罗兆2");
list.add("罗兆3");
Iterator<String> iterator = list.iterator();
//迭代器方式进行遍历
while (iterator.hasNext()){
String s = iterator.next();
if (s.equals("罗兆2")){
//当add的时候,一、这个地方modCount会进行累加,当进行第二次循环时候,这个时候
//next方法会调用二、这个地方的方法checkForComodification();进行检查,如果不相等就会抛出异常
list.add("罗兆4");
}
}
//ArrayList所实现的抽象类。
public abstract AbstractList{
protected transient int modCount = 0;//实际修改的初值
}
public interface List<E>{
Iterator<E> iterator();//接口的实例要实现迭代器
boolean add(E e); //要实现add方法。
}
public ArrayList(){
一、 public boolean add(E e) {//当list.add()时候,这个时候实际修改的值,会进行自增
modCount++;
add(e, elementData, size);
return true;
}
//相比迭代器,而言get方法执行后,不会把modCount进行累加,所以
//在ArrayList调用get方法时候不会调用约束检查,所以也就不会抛出异常。
/**
* for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals("张三")){
list.add("李世明");
}
}
*/
三、public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}
}
private class Itr implements Iterator<E> {
int expectedModCount = modCount;//把实际修改的值,赋值给预期修改的值
@SuppressWarnings("unchecked")
public E next() {
//每当我获取当前游标指向的记录时候,都进行检查,实际修改值和预期修改值是否相等
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
二、final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
1、迭代器遍历集合且直接用集合删除元素的时候可能出 现。
2、增强for循环遍历集合且直接用集合删除元素的时候可能出现。
增强for循环就是迭代器的变种
二、那种遍历且删除元素不会出现问题
1、迭代器遍历集合,但是用的是迭代器自己的删除方法操作就可以解决。
2、使用for循环遍历,并删除元素不会存在问题。
而通过下标方式进行添加,就不会抛出异常。
3、第三种List集合可以通过自己的listiterator迭代器就不会出现问题 列表迭代器
是通过List集合的listiterator()方法得到,所以说它是List集合特有的迭代器。
用的比较少,了解即可,但是 该列表迭代器中add可以避免并发修改异常的问题。
因为该add方法modCount没有进行累加。是进行的赋值,所以没有并发修改异常的情形。
List<String> list=new ArrayList<>();
list.add("张三");
list.add("张三1");
list.add("张三2");
list.add("张三3");
list.add("张三4");
ListIterator<String> listIterator = list.listIterator();
//按顺序进行遍历
/* while (listIterator.hasNext()){
String next = listIterator.next();
System.out.println(next);
}
System.out.println("-----------");
//通过列表迭代器,对元素从最后向前,进行倒置输出
while (listIterator.hasPrevious()){
String previous = listIterator.previous();
System.out.println(previous);
}*/
while (listIterator.hasNext()){
String next = listIterator.next();
if (next.equals("张三1")){
listIterator.add("罗兆1");
}
}
System.out.println(list);