在以下四種遍歷過程中,前兩種會拋出ConcurrentModificationException,而后兩種方法是正確的.
Department類:
package com.sitinspring;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Department {
private String name;
private List<Member> memberSheet;
public Department(String name) {
this.name = name;
}
public void addMemer(Member member) {
if (memberSheet == null) {
memberSheet = new ArrayList<Member>();
}
memberSheet.add(member);
}
public void printMemberSheet() {
System.out.println("----部門" + name + "人員名單---");
for (Member member : memberSheet) {
System.out.println(member);
}
}
/**
* 里面的四個清除過程請分別獨立執行
*
*/
public void removeYoungerFromMemberSheet() {
// 遍歷一:這個處理會拋出java.util.ConcurrentModificationException
for (Member member : memberSheet) {
if (member.getAge() < 30) {
memberSheet.remove(member);
}
}
// 遍歷二:這個處理也會拋出java.util.ConcurrentModificationException
for (Iterator it = memberSheet.iterator(); it.hasNext();) {
Member member = (Member) it.next();
if (member.getAge() < 30) {
memberSheet.remove(member);
}
}
// 遍歷三:這個處理調用Iterator 本身的方法 remove(),會正常執行
for (Iterator it = memberSheet.iterator(); it.hasNext();) {
Member member = (Member) it.next();
if (member.getAge() < 30) {
it.remove();
}
}
// 遍歷四:這個處理不依賴Iterator,也會正常執行
for (int i=0;i<memberSheet.size();i++) {
Member member = memberSheet.get(i);
if (member.getAge() < 30) {
memberSheet.remove(member);
}
}
}
public String toString() {
return name;
}
public String getName() {
return name;
}
public static void main(String[] args) {
Department resarchDept = new Department("研發部門");
resarchDept.addMemer(new Member("張三", 38));
resarchDept.addMemer(new Member("李四", 24));
resarchDept.addMemer(new Member("王五", 30));
resarchDept.addMemer(new Member("錢七", 22));
resarchDept.addMemer(new Member("孫八", 39));
resarchDept.addMemer(new Member("周九", 30));
resarchDept.removeYoungerFromMemberSheet();
resarchDept.printMemberSheet();
}
}
Member類:
package com.sitinspring;
public class Member{
private String name;
private int age;
private Department department;
public Member(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
StringBuffer sb=new StringBuffer();
sb.append("員工名="+name);
sb.append(" 年齡="+age);
if(department!=null){
sb.append(" 所屬部門="+department);
}
return sb.toString();
}
public void changeNewDepartment(Department newDepartment) {
department.removeMemer(name);
newDepartment.addMemer(this);
}
public String getName() {
return name;
}
public void setDepartment(Department department) {
this.department = department;
}
}
為什么會發生這樣的結果呢?這是因為
"
當使用 fail-fast iterator 對 Collection 或 Map 進行迭代操作過程中嘗試直接修改 Collection / Map 的內容時,即使是在單線程下運行, java.util.ConcurrentModificationException 異常也將被拋出。
Iterator 是工作在一個獨立的線程中,并且擁有一個 mutex 鎖。 Iterator 被創建之后會建立一個指向原來對象的單鏈索引表,當原來的對象數量發生變化時,這個索引表的內容不會同步改變,所以當索引指針往后移動的時候就找不到要迭代的對象,所以按照 fail-fast 原則 Iterator 會馬上拋出 java.util.ConcurrentModificationException 異常。
所以 Iterator 在工作的時候是不允許被迭代的對象被改變的。但你可以使用 Iterator 本身的方法 remove() 來刪除對象, Iterator.remove() 方法會在刪除當前迭代對象的同時維護索引的一致性。"
上述這段資料來自http://hi.baidu.com/xjenator/blog/item/23b235a89041d4b0ca130c16.html.
java.util包中很多迭代器都是所謂的fail-fast迭代器.這些迭代器如果發現集合被修改,而且不是通過迭代器本身,那么拋出一個異常進行清除-
ConcurrentModificationException-從而避免不安全行為的發生.
因此,第三種采用it.remove();不會出現任何異常,而第四不依賴于Iterator而依賴于索引當然更不會出現異常.
代碼下載:
http://www.tkk7.com/Files/sitinspring/ConcurrentModificationTest20071203210937.rar