一、遍历集合的方式有很多,这里就以List 为例
如果是单线程的我们一般使用: int len= list.size()
如果是多线程的程序,我们就用Iterator 迭代器来遍历:
两种方式,在使用Iterator遍历中如果我们直接使用集合的remove方法来删除则会报异常而如果我们使用Iterator 实例的remove方法来删除的话则正常,这个大家都知道,但为什么?
1、使用Iterator 的remove方法来删除:ArrayList中Iterator 的源码:
2、直接调用集合的remove方法:
上面的实例中是Iterator的remove方法和Collection的remove方法,而如果是add方法则也是同样的原理。
通过这两段代码我们发现出现异常的原因:
当集合使用Iterator进行迭代的时候,实际是new Itr()创建一个内部对象,初始化包含对象个数,可以理解为在独立线程中操作的。Iterator创建之后引用指向原来的集合对象。当原来的对象数量发生变化时,这个内部对象索引表内容其实是不会同步的。所以,当索引指针往后移动的时候就找不到要迭代的对象了。内部对象操作时为了避免这种情况都会通过checkForComodification方法检测是否一致,不一致提前抛出异常ConcurrentModifiedException。
异常解决办法:
Iterator 支持从源集合中安全地删除对象,只需在 Iterator 上调用 remove() 即可。这样做的好处是可以避免 ConcurrentModifiedException ,这个异常顾名思意:当打开 Iterator 迭代集合时,同时又在对集合进行修改。有些集合不允许在迭代时删除或添加元素,但是调用 Iterator 的 remove() 方法是个安全的做法。
调用Iterator 的remove方法时不仅修改了集合的个数也修改了内部对象的个数,这样再调用checkForComodification() 方法进行检测的时候发现原来集合对象的个数和内部对象的个数相同这样自然就没异常了
总结:
如果调用Iterator 的remove() 方法来删除的话,则iterator的内部对象个数和原来集合中对象的个数会保持同步,而直接调用集合的remove方法来删除的话,集合中对象的个数会变化而Iterator 内部对象的个数不会变化,当调用Iterator 的next 遍历的时候发现集合中的对象的个数和Iterator 内部对象的个数不同,这样指针往后移动的时候就找不到要迭代的对象。这是报异常的主要原因,但 内部对象操作时为了避免这种情况都会通过checkForComodification方法检测是否一致,不一致提前抛出异常ConcurrentModifiedException。