打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
[Java拾遗]迭代list过程中删除元素
             今天在翻看HDFS中FSImage初始化部分时,其中有段代码是这样的:
Java代码  
  1. for (URI dirName : fsNameDirs) {  
  2.       boolean isAlsoEdits = false;  
  3.       for (URI editsDirName : fsEditsDirs) {  
  4.           if (editsDirName.compareTo(dirName) == 0) {  
  5.                isAlsoEdits = true;  
  6.                fsEditsDirs.remove(editsDirName);  
  7.                break;  
  8.           }  
  9.       }  
  10. }  

        根据以往经验,这段代码可能会有ConcurrentModificationException发生。在向他们指出这个问题前,我写了简单几句测试代码来提前验证下。

        代码一:

Java代码  
  1. List<String> list = new ArrayList<String>();  
  2. list.add("a");  
  3. list.add("b");  
  4. list.add("c");  
  5.           
  6. for (String str : list) {  
  7.     if (str.equals("a")) {  
  8.         list.remove(str);  
  9.     }  
  10. }  
  11.           
  12. System.out.println(list);  

        代码一的结果如预期抛出异常。因为在迭代过程中再去删除元素,会造成迭代索引有问题。于是我又随手修改了下判断条件,删除list不同位置的元素。大家看下面这个例子,它的结果应该是什么?


        代码二:

Java代码  
  1. List<String> list = new ArrayList<String>();  
  2. list.add("a");  
  3. list.add("b");  
  4. list.add("c");  
  5.           
  6. for (String str : list) {  
  7.     if (str.equals("b")) {  
  8.        list.remove(str);  
  9.     }  
  10. }  
  11.           
  12. System.out.println(list);  

        代码二的运行结果是正常的:[a, c]。

        这让我比较迷惑了。接着试了几次后发现,在一个list中,只有删除倒数第二个元素时是正常的,删除其它位置都会有异常抛出。于是我翻看了AbstractList中的迭代实现,主体是下面这三段代码


Java代码  
  1. public boolean hasNext() {  
  2.     return cursor != size();  
  3. }  
  4.   
  5. public E next() {  
  6.     checkForComodification();  
  7.     try {  
  8.          E next = get(cursor++);  
  9.          return next;  
  10.      } catch (IndexOutOfBoundsException e) {  
  11.          checkForComodification();  
  12.          throw new NoSuchElementException();  
  13.      }  
  14. }  
  15.   
  16. final void checkForComodification() {  
  17.     if (modCount != expectedModCount)  
  18.          throw new ConcurrentModificationException();  
  19.     }  
  20. }  

       cursor标示着当前list的索引,不断地与list size比对。如果hasNext返回true,会紧接着执行next方法,在next方法中检查当前list有没有被修改过。

        在list迭代过程中,如果删除一个元素,那么size就减一,hasNext提前结束,迭代不会到达list的最后一个元素。也就是说,如果在迭代到list倒数第二个元素时删除此元素,接下来的hasNext会返回false,迭代结束,不会进入next方法中做检查,也就不会出什么问题。而除此之外的其它情况下,hasNext都是true,接下来的next方法检查时会产生异常。

        问题让我很疑惑,但分析后的原理很简单。惟一感觉与平时想法不一样的地方是它对hasNext的判断条件有些奇怪。它没有以cursor小于list size来判断,而是取它俩是否相等,在cursor超过size时,又在从list中get元素时施以IndexOutOfBound的弥补。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
java集合中的一个移除数据陷阱(遍历集合自身并同时删除被遍历数据)
Java集合Collection和泛型
Java迭代 : Iterator和Iterable接口
java提高篇(三十)
Iterator、Iterable接口的使用及详解
简说设计模式——迭代器模式
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服