新浪微博:IT國(guó)子監(jiān)(記得關(guān)注噢) http://weibo.com/itguozijian
下面是網(wǎng)上的其他解釋,更能從本質(zhì)上解釋原因: Iterator 是工作在一個(gè)獨(dú)立的線程中,并且擁有一個(gè) mutex 鎖。 Iterator 被創(chuàng)建之后會(huì)建立一個(gè)指向原來(lái)對(duì)象的單鏈索引表,當(dāng)原來(lái)的對(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() 來(lái)刪除對(duì)象, Iterator.remove() 方法會(huì)在刪除當(dāng)前迭代對(duì)象的同時(shí)維護(hù)索引的一致性。
在java常用的集合框架就是list ,set ,map 。 list 可通過(guò)下標(biāo)進(jìn)行遍歷,set,map不能通過(guò)下表進(jìn)行遍歷,因此對(duì)于set ,map的數(shù)據(jù)遍歷時(shí),常常采用迭代器,不過(guò)在使用迭代器移除數(shù)據(jù)時(shí)存在陷阱。 執(zhí)行如下代碼: Set set = new HashSet(); set.add(1); set.add(2); set.add(3); Iterator i = set.iterator(); while(i.hashNext()){ Object o = i.next(); set.remove(o); } 執(zhí)行結(jié)果會(huì)出現(xiàn)以下異常: Exception in thread "main" java.util.ConcurrentModificationException at java.util.AbstractList$Itr.checkForComodification(Unknown Source) at java.util.AbstractList$Itr.next(Unknown Source) 這個(gè)問(wèn)題在集合框架使用迭代器遍歷數(shù)據(jù)時(shí)存在,在java5新曾的foreach遍歷方式下也存在。在通過(guò)下表遍歷list的過(guò)程中不存在著個(gè)問(wèn)題。 如: List list = new ArrayList(); list .add(1); list.add(2); list.add(3); for(int i = 0 ; i < list.size();i++){ list.remove(list.get(i));|| list.remove(i); } // 或者使用iterator的remove方法
代碼能夠正常執(zhí)行。 當(dāng)然這種情況也是容易解決,實(shí)現(xiàn)方式就是講遍歷與移除操作分離,即在遍歷的過(guò)程中,將需要移除的數(shù)據(jù)存放在另外一個(gè)集合當(dāng)中,遍歷結(jié)束之后,統(tǒng)一移除。 ------------------------------------------------------------------------------------------------------利用java迭代器Itetator遍歷并刪除HashMap中的元素問(wèn)題
問(wèn)題: 下面的代碼試圖利用HashMap的Iterator對(duì)象遍歷該HashMap并刪除滿足條件的元素(比如超時(shí)的元素),但會(huì)拋出java.util.ConcurrentModificationException異常 public static void main(String[] args) { HashMap<String, String> hs=new HashMap(); hs.put("p1", "1"); hs.put("p2", "1"); hs.put("p3", "1"); hs.put("p4", "1"); hs.put("p5", "1"); hs.put("p6", "1"); Iterator it=hs.keySet().iterator(); while(it.hasNext()) { String str=(String)it.next(); System.out.println(hs);
//邏輯處理......... ............. hs.remove(str); } } 原因應(yīng)該是hs.remove(str)后,it內(nèi)容沒(méi)變,并且it里的指針列表又重新排序,所以只要確保刪除任一元素后,it保持同步更新即可: 解決方案一:刪除任一元素后,it保持同步更新 ............ Iterator it=hs.keySet().iterator(); while(it.hasNext()) { it=hs.keySet().iterator(); String str=(String)it.next(); System.out.println(hs);
//邏輯處理......... ............. hs.remove(str); } ........... 這樣的時(shí)間復(fù)雜度明顯太大(兩層循環(huán)嵌套) 解決方案二: 由于刪除元素時(shí),hs的iterator對(duì)象也重新排序,所以只要用hs的一個(gè)副本hsBack Uackp的iterator去遍歷hs即可,這樣在刪除hs元素時(shí)iterator就不會(huì)重排了(因?yàn)閯h除的是hs的元素,而不是該iterator所屬的hsBackUackp) ................... hsBackUp=(HashMap<String, String>)hs.clone(); Iterator it=hsBackUp.keySet().iterator(); System.out.println(hsBackUp); while(it.hasNext()) { String str=(String)it.next(); System.out.println(hs); hs.remove(str); } ..................... 這樣雖然時(shí)間復(fù)雜度小了(只有一層循環(huán)),可是空間復(fù)雜度大了(多了一個(gè)hashmap的拷貝); 查閱api文檔和相關(guān)資料后,原來(lái)iterator對(duì)象有一remove方法:void remove() Removes from the underlying collection the last element returned by the iterator (optional operation). This method can be called only once per call to next. The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method. 于是有下面的改進(jìn): 解決方案三: .............................. Iterator it=hs.keySet().iterator(); while(it.hasNext()) { String str=(String)it.next(); System.out.println(hs); it.remove(); } ..............................
|