A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 于星星 中级黑马   /  2012-7-18 21:31  /  2259 人查看  /  9 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

public class  TestIterator{

        public static void main(String[] args) {

                List<String> aList = new ArrayList<String>();
                aList.add("aaa");
                aList.add("bbb");
                aList.add("asdf");
                aList.add("jvaa");
                aList.add("aaaa");
                aList.add("itcast");

                System.out.println(aList);
                delElements1(aList);
                delElements2(aList);
                delElements3(aList);
                System.out.println(aList);
        }

        public static void delElements1(List<String> aList) {
                for (String str : aList) {
                        if (str.equals("aaa")) {
                                aList.remove(str);
                        }
                }
        }

        public static void delElements2(List<String> aList){
                Iterator<String> it = aList.iterator();
                while(it.hasNext()){
                        String str = it.next();
                        if(str.equals("aaa")){
                                aList.remove(str);
                        }
                }
        }
       
        public static void delElements3(List<String> aList){
                        Iterator<String> it = aList.iterator();
                         while(it.hasNext()){
                        String str = it.next();
                        if(str.equals("aaa")){
                                it.remove();
                        }
                 }
        }
}
以上代码中delElements1,delElements2都会报异常:Exception in thread "main" java.util.ConcurrentModificationException,而delElements3则不会报异常,请问这是为什么呢?

评分

参与人数 1技术分 +1 收起 理由
刘笑 + 1 赞一个!

查看全部评分

9 个回复

倒序浏览
1、首先高级for语句的底层实现用到了Interator,所以delElements1,delElements2属于相同的问题
2、再次,集合的元素就是用迭代器Interator来取出操作的,delElements1,delElements2,这两个方法你都是用集合去remove();用迭代器取出的元素只能用迭代器的方法去操作。你这是用集合的方法操作迭代器取出来的元素。方法3是正确的。
回复 使用道具 举报
本帖最后由 王宝康 于 2012-7-18 22:09 编辑

             当通过Collection集合的Iterator()方法得到一个iterator对象后,如果当前线程或其他线程接着又通过Collection集合的一些方法对集合进行了修改操作(调用当前Iterator对象的remove()方法来修改集合除外),接下来访问这个Iterator对象的next()方法会导致java.util.ConcurrentException运行时异常。
           以上摘自孙伟琴《java面向对象编程》第四版,
           我对此的理解是,你用Iterator对象才操作集合时,又通过集合的其它方法对集合元素进行修改(该方法对元素的获取原理不是Iterator),相当于两个人对一缸水进行操作,你Iterator可能在去睡,我Collection可能在取水也可能在灌水,这时候,这缸水的状态就取决于两个对象了,Iterator和Collection,而调用当前Iterator对象的remove()方法来修改集合除外,就是一个Iterator不可能是在同一时间又取水又灌水,对这缸水进行操作的只有Iterator自己,所以缸里的水就不会出现状态异常了。

评分

参与人数 1技术分 +1 收起 理由
刘笑 + 1 赞一个!

查看全部评分

回复 使用道具 举报
1,2都报出异常,属于集合修改并发异常,指的是在集合迭代过程中,集合内部元素发生了改变,导致迭代器无法执行。
public static void delElements2(List<String> aList){
                 Iterator<String> it = aList.iterator();
                 while(it.hasNext()){
                         String str = it.next();
                         if(str.equals("aaa")){
                                 aList.remove(str);//删除了aList的元素“aaa”,改变了集合的结构。在迭代时,不可以通过集合对象的方法操作集合中的元素,否则报异常。
                         }
                 }
         }
第一个方法,用增强型for循环,遍历list。其实就是第二个方法的简写,也是迭代器的问题,所以也会报出和第二个一样的异常。

评分

参与人数 1技术分 +1 收起 理由
刘笑 + 1 赞一个!

查看全部评分

回复 使用道具 举报
本帖最后由 位丹丹 于 2012-7-18 22:08 编辑


不清楚你写的代码的目的是什么,怎么感觉你后面三段代码是重复的,另外迭代器的remove的操作是remove(index),指删除指定位置的元素。
回复 使用道具 举报
高级for循环变量集合底层也是使用的迭代功能  而在迭代的同时某些情况下用集合的增删方法会导致快速失败异常问题
快速失败异常的产生原因为 集合有一个modCount属性 当你用集合的某些方法时(如真加 删除 清除元素等)则该modCout会++ 迭代时迭代器有一个xxModCount属性 当你获取一个集合的迭代是 会把modCount赋值i给
xxModCount 普通迭代器除了hasNext其他方法都会首先调用快速失败异常方法 该方法会检测你的xxModCount是否等于集合的modCount如果不等于抛快速失败异常 而普通迭代器的remove方法原理是首先调用集合的remove方法 结果为true时则让xxModCount++ 这也是你前几个方法抛快速异常 用迭代器remove的方法不抛异常的原因 当然你想要在迭代的同时用集合的添加和删除功能也是可以的  你只要调用了集合的某些方法以后不在使用普通迭代器除了hsNext方法以外的方法就行了  你要在remove后面加个break;就不会抛异常了 或者删除的是aaaa原始也不会抛异常  只要理解了快速失败的原理 就能更好的更简单的操作集合
CopyOnWriteArraySet CopyOnWriteArrayList  这2个类除了同步以外 也可以在迭代的同时利用集合的crud功能没有快速失败的可能发生
回复 使用道具 举报
迭代器操作时不允许你在进行增删;就像ListIterator为什么要比Iterator强大。就是加入了set等操作;
操作数据只有一种方法remove在Iterator中,而你要加入数据就不可以了;这里你用到了aList的方法,如果这个remove可用,那么其他方法就可以用了;
很显然不可以;
其实,也可以考虑一下这一方面,应该了解为什么要有迭代器:迭代器是为了以后再修改原始容器的时候,不必改变遍历的代码;也就是如果以前是Arraylist改成linkedList了你就不必改变Iterator中的代码了;但是如果你加入了该方法的特有方法;比如addfrist();是不是会破坏这种代码重构的方便性?
回复 使用道具 举报
位雪 中级黑马 2012-7-18 22:20:23
8#
本帖最后由 位丹丹 于 2012-7-18 22:22 编辑
周坤 发表于 2012-7-18 22:04
1,2都报出异常,属于集合修改并发异常,指的是在集合迭代过程中,集合内部元素发生了改变,导致迭代器无法 ...


追问一下,为什么把代码稍改一下即delElements1、delElements2中remove中str换成aList,就不会报错呢?
  1. package cn.itcast.interview.exercise;

  2. import java.util.ArrayList;
  3. import java.util.Iterator;
  4. import java.util.List;

  5. public class  TestIterator{

  6.     public static void main(String[] args) {

  7.             List<String> aList = new ArrayList<String>();
  8.             aList.add("aaa");
  9.             aList.add("bbb");
  10.             aList.add("asdf");
  11.             aList.add("jvaa");
  12.             aList.add("aaaa");
  13.             aList.add("itcast");

  14.             System.out.println(aList);
  15.             delElements1(aList);
  16.             delElements2(aList);
  17.             delElements3(aList);
  18.             System.out.println(aList);
  19.     }

  20.     public static void delElements1(List<String> aList) {
  21.             for (String str : aList) {
  22.                     if (str.equals("aaa")) {
  23.                             aList.remove( aList);
  24.                     }
  25.             }
  26.     }

  27.     public static void delElements2(List<String> aList){
  28.             Iterator<String> it = aList.iterator();
  29.             while(it.hasNext()){
  30.                     String str = it.next();
  31.                     if(str.equals("aaa")){
  32.                             aList.remove(aList);
  33.                     }
  34.             }
  35.     }
  36.    
  37.     public static void delElements3(List<String> aList){
  38.                     Iterator<String> it = aList.iterator();
  39.                      while(it.hasNext()){
  40.                     String str = it.next();
  41.                     if(str.equals("aaa")){
  42.                             it.remove();
  43.                     }
  44.              }
  45.     }
  46. }
复制代码

未命名.jpg (6.77 KB, 下载次数: 19)

未命名.jpg
回复 使用道具 举报
位丹丹 发表于 2012-7-18 22:06
不清楚你写的代码的目的是什么,怎么感觉你后面三段代码是重复的,另外迭代器的remove的操作是remove(ind ...

同学,我查了下API
然后Iterator的remove操作是这样的吧?
void remove()从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。每次调用 next 只能调用一次此方法。如果进行迭代时用调用此方法之外的其他方式修改了该迭代器所指向的 collection,则迭代器的行为是不确定的。
回复 使用道具 举报
位丹丹 发表于 2012-7-18 22:20
追问一下,为什么把代码稍改一下即delElements1、delElements2中remove中str换成aList,就不会报错呢? ...

while(it.hasNext()){

37.                    String str = it.next();

38.                    if(str.equals("aaa")){

39.                            aList.remove(aList);//应该是remove失败吧,这个操作没有对集合产生影响。

40.                    }

41.            }

aList.remove(aList),只有remove为aList集合中的元素时,aList集合才会变化,比如你随便remove一个类,那么集合aList没有变化。至于打印结果,那是第三个方法移除成功了,如果把那个方法屏蔽掉,结果为原来的集合。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马