Iterator迭代器
Iterator接口定义了以下四种方法。
方法 | 作用 |
---|---|
boolean hasNext() | 如果集合还没遍历完就返回true。 |
Object next() | 返回集合里的下一个元素。 |
void remove() | 删除集合里上一次next方法返回的元素。 |
void forEachRemaining(Consumer action) | 这是java8新增的默认方法,可用Lambda表达式遍历数组。 |
一、使用迭代器遍历元素时不能不能通过Collection接口中的remove方法删除元素,只能用Interator的remove方法删除元素。否者会报ConcurrentModificationException并发修改异常
/* 建立一个Collection */
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
/* 迭代器遍历集合 */
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String str = it.next();//java.util.ConcurrentModificationException并发修改异常
System.out.println(str);
if("B".equals(str)) {
list.remove(str);
}
}
运行结果:
源码分析
迭代器其实在另外一个线程复制了一个一摸一样的集合进行遍历的。当用集合的remove方法删除元素时,迭代器是不会知道的,所以就会抛出异常。
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];
}
而用迭代器的ramove方法删除元素时,实际在底层还是用的集合的remove方法,所以迭代器和集合修改元素的次数一样是不会出现异常的。
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);//用的还是集合的remove方法
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
二、但是Arraylist迭代器会出现下面这种情况,当我们用集合删除方法删除倒数第二个元素时,并不会出现异常。
/* 建立一个Collection */
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
/* 迭代器遍历集合 */
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String str = it.next();//java.util.ConcurrentModificationException并发修改异常
System.out.println(str);
if("C".equals(str)) {
list.remove(str);
}
}
运行结果:
源码分析
public boolean hasNext() {
return cursor != size;//根据上面的说法在循环第四次是返回的是false,不会执行循环里的的代码
}
当while循环遍历到“C”,执行完it.next()方法后cursor值为3,接着删除“C”这个元素后,集合的size变成了3。当继续第四次循环时现判断hasNext()当cursor值和size值相等时返回false,所以不会执行while循环里面的语句,自然不会执行next()方法,所以时不会出现异常的。虽然没有出现异常,但是还是有问题的,那就是并没有遍历最后一位。
所以使用迭代器遍历时,不要使用集合的remove方法和add方法。要使用迭代器的方法。下面是正常运行的
/* 建立一个Collection */
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
/* 迭代器遍历集合 */
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String str = it.next();
System.out.println(str);
if("C".equals(str)) {
it.remove();//使用迭代器删除
}
}