当选用迭代器进行遍历时需要注意的问题

今天Alei写了一段让人感到非常疑惑的代码:

public static void main(String[] args) {
    Collection c = new ArrayList();
    c.add(new Name("fff1", "lll1"));
    c.add(new Name("f1", "l1"));
    c.add(new Name("fff3", "lll3"));
    for(Iterator i = c.iterator(); i.hasNext();) {
        Name name = (Name)i.next();
        if(name.getFirstName().length() < 3) {
            i.remove();
//          c.remove(name); //此方法会产生例外(异常)?
        }
    }
    System.out.println(c);
}

class Name {
    private String firstName, lastName;
    public Name(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }
	
    public String toString() {
        return firstName + " " + lastName;
    }
	
    public boolean equals(Object obj) {
        if(obj instanceof Name) {
            Name name = (Name)obj;
            return firstName.equals(name.firstName)
                    && lastName.equals(lastName);
        }
        return super.equals(obj);
    }

    public int hashCode() {
        return firstName.hashCode();
    }
}

在 main 方法里的代码略显诡异,众所周知,在使用迭代器进行遍历时,若有删除容器里某元素的操作,一定要使用这个容器类迭代器的 remove() 方法,而不能使用容器对象的 remove() 方法。

认真看下 ArrayList 类的源码就能发现:

ArrayList 采用 size 属性来维护自已的状态,而 Iterator 采用 cursor(游标)来来维护自已的状态。

当 size 出现变化时,cursor 并不一定能够得到同步,除非这种变化是 Iterator 主动导致的。当 Iterator.remove() 方法导致 ArrayList 列表发生变化时,他会更新 cursor 来同步这一变化。但其他方式导致的 ArrayList 变化,Iterator 是无法感知的。ArrayList 自然也不会主动通知 Iterator 们,那将是一个繁重的工作。Iterator 到底还是做了努力:为防止状态不一致可能引发的“无法设想的后果”,Iterator 会经常做 checkForComodification 检查,以防有变。如果有变,则抛出异常。

如果对正在被迭代的集合进行结构上的改变(即对该集合使用 add、remove 或 clear 方法),那么迭代器就不再合法(并且在其后使用该迭代器将会有 ConcurrentModificationException 异常被抛出)。

如果使用迭代器自己的 remove 方法,那么这个迭代器就仍然是合法的。

然并卵,当我使用 c.remove() 方法时,程序尽然没有抛出异常!!!!!!

于是我又敲出下面代码并运行:

List<String> famous = new ArrayList<String>();
famous.add("liudehua");
famous.add("huaiyirensheng");
famous.add("liushishi");
famous.add("tangwei");
for (String s : famous) {
    if (s.equals("huaiyirensheng")) {
        famous.remove(s);
    }
}

//以上代码中的循环等同于:
for(Iterator<String> it = famous.iterator();it.hasNext();){
    String s = it.next();
    if(s.equals("huaiyirensheng")){
        famous.remove(s);
    }
}

于是抛出异常:

java.util.ConcurrentModificationException

这下我就懵B了,这是怎么回事呀?我开始怀疑自己的人生!!!!!!!

上面的循环如果改成下面这样:

for (int i = 0; i < famous.size(); i++) {
    String s = famous.get(i);
    if (s.equals("huaiyirensheng")) {
        famous.remove(s);
    }
}

那跟迭代器半毛钱关系都没有了!难道我一开始写的那些代码跟迭代器没半毛钱关系?跪求大神解答我这个小白的低级问题!

转载于:https://my.oschina.net/u/3637389/blog/1843850

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值