java foreach不适用的一种情况

今天遇到 java.util.ConcurrentModificationException,从网上找到如下文章

遍历集合找到特定的元素并将其删除,两种实现:

     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.javaeye.com/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.javaeye.com/topic/145383  同意这种解释,从代码出发,比较好理解。 

http://gceclub.sun.com.cn/yuanchuang/week-14/iterator.html

 

 

 

嗯,是否有还使用foreach的解决方案?

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值