在以下四種遍歷過程中,前兩種會(huì)拋出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); } } /** * 里面的四個(gè)清除過程請(qǐng)分別獨(dú)立執(zhí)行 * */ public void removeYoungerFromMemberSheet() { // 遍歷一:這個(gè)處理會(huì)拋出java.util.ConcurrentModificationException for (Member member : memberSheet) { if (member.getAge() < 30) { memberSheet.remove(member); } } // 遍歷二:這個(gè)處理也會(huì)拋出java.util.ConcurrentModificationException for (Iterator it = memberSheet.iterator(); it.hasNext();) { Member member = (Member) it.next(); if (member.getAge() < 30) { memberSheet.remove(member); } } // 遍歷三:這個(gè)處理調(diào)用Iterator 本身的方法 remove(),會(huì)正常執(zhí)行 for (Iterator it = memberSheet.iterator(); it.hasNext();) { Member member = (Member) it.next(); if (member.getAge() < 30) { it.remove(); } } // 遍歷四:這個(gè)處理不依賴Iterator,也會(huì)正常執(zhí)行 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("研發(fā)部門"); 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; } } 為什么會(huì)發(fā)生這樣的結(jié)果呢?這是因?yàn)?br> "當(dāng)使用 fail-fast iterator 對(duì) Collection 或 Map 進(jìn)行迭代操作過程中嘗試直接修改 Collection / Map 的內(nèi)容時(shí),即使是在單線程下運(yùn)行, java.util.ConcurrentModificationException 異常也將被拋出。 Iterator 是工作在一個(gè)獨(dú)立的線程中,并且擁有一個(gè) mutex 鎖。 Iterator 被創(chuàng)建之后會(huì)建立一個(gè)指向原來對(duì)象的單鏈索引表,當(dāng)原來的對(duì)象數(shù)量發(fā)生變化時(shí),這個(gè)索引表的內(nèi)容不會(huì)同步改變,所以當(dāng)索引指針往后移動(dòng)的時(shí)候就找不到要迭代的對(duì)象,所以按照 fail-fast 原則 Iterator 會(huì)馬上拋出 java.util.ConcurrentModificationException 異常。 所以 Iterator 在工作的時(shí)候是不允許被迭代的對(duì)象被改變的。但你可以使用 Iterator 本身的方法 remove() 來刪除對(duì)象, Iterator.remove() 方法會(huì)在刪除當(dāng)前迭代對(duì)象的同時(shí)維護(hù)索引的一致性。" 上述這段資料來自http://hi.baidu.com/xjenator/blog/item/23b235a89041d4b0ca130c16.html. java.util包中很多迭代器都是所謂的fail-fast迭代器.這些迭代器如果發(fā)現(xiàn)集合被修改,而且不是通過迭代器本身,那么拋出一個(gè)異常進(jìn)行清除-ConcurrentModificationException-從而避免不安全行為的發(fā)生. 因此,第三種采用it.remove();不會(huì)出現(xiàn)任何異常,而第四不依賴于Iterator而依賴于索引當(dāng)然更不會(huì)出現(xiàn)異常. 代碼下載: http://www./Files/sitinspring/ConcurrentModificationTest20071203210937.rar |
|