java foreach不适用的一种情况

    技术2022-05-12  25

    今天遇到 java.util.ConcurrentModificationException,从网上找到如下文章 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)