分享

java iterator

 Ethan的博客 2011-10-18
。遍历集合找到特定的元素并将其删除,两种实现:
    private void testDelete() {
         List
<String> list = new ArrayList<String>();
        
for (int i = 0; i < 10; i++) {
             String str
= "ck0" + i;
             list.add(str);
         }

        
for (Iterator it = list.iterator(); it.hasNext();) {
             String str
= (String) it.next();
            
if (str.equals("ck05")) {
                
// list.remove(str);  // 第一种删除方法
                 it.remove();  // 第二种删除方法
             }
         }
     }
当通过list.remove(str)删除时报异常:java.util.ConcurrentModificationException。而通过it.remove()删除时一切正常。

先看看List中的remove方法:

这里用的ArrayList,ArrayList中remove方法源代码:

    public boolean remove(Object o) {
        
if (o == null) {
            
for (int index = 0; index < size; index++)
                
if (elementData[index] == null) {
                     fastRemove(index);
                    
return true;
                 }
         }
else {
            
for (int index = 0; index < size; index++)
                
if (o.equals(elementData[index])) {
                     fastRemove(index);
                    
return true;
                 }
         }
        
return false;
     }

    
private void fastRemove(int index) {
         modCount
++; // 特别注意这里,这里只增加了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
     }

到这里似乎还没有找到抛出异常的地方,接着看。删除后得到下一个元素的代码,it.next(): it为AbstractList的内部类Iterator的一个实例。

    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();
     }

也就是集合被修改的次数(modCount)和它的期望值(expectedModCount)不同,那么就会抛出ConcurrentModificationException异常。

再来看看Iterator的remove()方法的源代码:

    public void remove() {
        
if (lastRet == -1)
            
throw new IllegalStateException();
         checkForComodification();
        
try {
             AbstractList.
this.remove(lastRet);
            
if (lastRet < cursor)
                 cursor
--;
             lastRet
= -1;
             expectedModCount
= modCount; // 设置expectedModCount
         } catch (IndexOutOfBoundsException e) {
            
throw new ConcurrentModificationException();
         }
     }

    
final void checkForComodification() {
        
if (modCount != expectedModCount)
            
throw new ConcurrentModificationException();
     }

到这里问题就很明白了!

在我们foreach时也会出现这种情况,但是在用普通的for循环却不会。

    for(String str : list){
        
if(str.equals("ck05")){
             list.remove(str);  
// 报异常
         }
     }


    
for(int i = 0; i < list.size(); i++){
         String str
= list.get(i);
        
if(str.equals("ck05")){
             list.remove(str);
// 正常
         }
     }

“之所以可以这样做(用foreach遍历集合),是因为Java SE5引入了新的的被称为Iterable的接口,该接口保护了一个能够产生Iterator的iterator()方法,并且Iterable接口被 foreach用来在序列中移动。”(<<Thinking in java>>)

网上其他解释:

http://www./topic/124788    

  文中指出:“有意思的是如果你的 Collection / Map 对象实际只有一个元素的时候, ConcurrentModificationException 异常并不会被抛出。这也就是为什么在 javadoc 里面指出: it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.” 测试了下,当只要一个元素时仍然会报异常!

http://www./topic/145383 同意这种解释,从代码出发,比较好理解。

http://gceclub./yuanchuang/week-14/iterator.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多