Iterator

  1. 正常的情况

    1. Iterator<Integer> iterator = list.iterator();
    2. while (iterator.hasNext()) {
    3. Integer next = iterator.next();
    4. System.out.println(next);
    5. }

    可以正常进行遍历

  2. 如果在便利的时候remove了一下

    1. Iterator<Integer> iterator = list.iterator();
    2. while (iterator.hasNext()) {
    3. Integer num = iterator.next();
    4. if (num.equals(1)) {
    5. list.remove(num);
    6. }
    7. }

    image.png

    异常名字 ConcurrentModificationException:同步修改异常,字面上的理解就是在迭代器在迭代元素的时候,原来arraylist数组发生了变化,这样就导致了异常。

    1. Iterator<Integer> iterator = list.iterator();
    2. 源码:
    3. public Iterator<E> iterator() {
    4. return new Itr();
    5. }
    6. Itr是一个内部类,它的部分源码:
    7. private class Itr implements Iterator<E> {
    8. int cursor; // index of next element to return 下一个要返回的元素
    9. int lastRet = -1; // index of last element returned; -1 if no such 上一个元素
    10. int expectedModCount = modCount; // expectedModCount 就是创建一个迭代器的时候,list数组才开始到现在的修改次数,后者是实际的修改次数
    11. // 在最开始的时候,两个是一样的

初始化一个Iterator以后,需要使用next

  1. public E next() {
  2. checkForComodification();
  3. int i = cursor; // cursor就是当前需要获取的元素
  4. if (i >= size)
  5. throw new NoSuchElementException();
  6. Object[] elementData = ArrayList.this.elementData;
  7. if (i >= elementData.length)
  8. throw new ConcurrentModificationException();
  9. cursor = i + 1; // cursor继续指向下一个元素
  10. return (E) elementData[lastRet = i]; // 返回地3行cursor的元素
  11. }
  12. final void checkForComodification() {
  13. if (modCount != expectedModCount) // 看下方函数
  14. throw new ConcurrentModificationException();
  15. }
  16. list.remove调用
  17. public E remove(int index) {
  18. rangeCheck(index);
  19. modCount++; // modCount 被修改了,与iterator的expectedModCount就不一致了
  20. E oldValue = elementData(index);
  21. int numMoved = size - index - 1;
  22. if (numMoved > 0)
  23. System.arraycopy(elementData, index+1, elementData, index,
  24. numMoved);
  25. elementData[--size] = null; // clear to let GC do its work
  26. return oldValue;
  27. }

再看一下iterator.remove()

  1. public void remove() {
  2. if (lastRet < 0)
  3. throw new IllegalStateException();
  4. checkForComodification();
  5. try {
  6. ArrayList.this.remove(lastRet);
  7. cursor = lastRet; // cursor 往前一个单位
  8. lastRet = -1; // 这个地方修改了lastRet,在看函数的第2行,会有异常,但是为什么没有呢?
  9. expectedModCount = modCount; //重置expectedModCount
  10. } catch (IndexOutOfBoundsException ex) {
  11. throw new ConcurrentModificationException();
  12. }
  13. }
  14. public E next() {
  15. checkForComodification();
  16. int i = cursor;
  17. if (i >= size)
  18. throw new NoSuchElementException();
  19. Object[] elementData = ArrayList.this.elementData;
  20. if (i >= elementData.length)
  21. throw new ConcurrentModificationException();
  22. cursor = i + 1;
  23. return (E) elementData[lastRet = i]; // 这个时候重新修改了lastRet,所以不会在remove()函数里面报异常
  24. }

从上面源码可以看出,如果连续两次iterator.remove(),那么还是会报错
image.pngimage.png