當選用迭代器進行遍歷時須要注意的問題

今天Alei寫了一段讓人感到很是疑惑的代碼:java

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() 方法。this

認真看下 ArrayList 類的源碼就能發現:code

ArrayList 採用 size 屬性來維護自已的狀態,而 Iterator 採用 cursor(遊標)來來維護自已的狀態。對象

當 size 出現變化時,cursor 並不必定可以獲得同步,除非這種變化是 Iterator 主動致使的。當 Iterator.remove() 方法致使 ArrayList 列表發生變化時,他會更新 cursor 來同步這一變化。但其餘方式致使的 ArrayList 變化,Iterator 是沒法感知的。ArrayList 天然也不會主動通知 Iterator 們,那將是一個繁重的工做。Iterator 到底仍是作了努力:爲防止狀態不一致可能引起的「沒法設想的後果」,Iterator 會常常作 checkForComodification 檢查,以防有變。若是有變,則拋出異常。rem

若是對正在被迭代的集合進行結構上的改變(即對該集合使用 add、remove 或 clear 方法),那麼迭代器就再也不合法(而且在其後使用該迭代器將會有 ConcurrentModificationException 異常被拋出)。get

若是使用迭代器本身的 remove 方法,那麼這個迭代器就仍然是合法的。同步

然並卵,當我使用 c.remove() 方法時,程序盡然沒有拋出異常!!!!!!源碼

因而我又敲出下面代碼並運行:hash

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);
    }
}

因而拋出異常:it

java.util.ConcurrentModificationException

這下我就懵B了,這是怎麼回事呀?我開始懷疑本身的人生!!!!!!!

上面的循環若是改爲下面這樣:

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

那跟迭代器半毛錢關係都沒有了!難道我一開始寫的那些代碼跟迭代器沒半毛錢關係?跪求大神解答我這個小白的低級問題!

相關文章
相關標籤/搜索