完成Java刪除一個聚集的多個元素。本站提示廣大學習愛好者:(完成Java刪除一個聚集的多個元素)文章只能為提供參考,不一定能成為您想要的結果。以下是完成Java刪除一個聚集的多個元素正文
成績
我須要從一個java的聚集中,依據另外一個聚集的內容,刪除第一個聚集中不特定的元素。這看上去異常簡略,但卻碰到了成績。
這是我要寫的辦法的頭部
private void screenBlackNameList(List<SharedBoardSmsWrapper> source, List<BlackNameListModel> blackNameList)
工作是如許子的。source聚集中保留了一些顯示用的數據元素。blackNameList聚集中保留的是黑名單列表。我們須要依據黑名單表,把source聚集中黑名單用戶的數據剔除失落。
這個成績的處理看上去異常簡略。
我起首應用for each 語句停止刪除。
for(SharedBoardSmsWrapper tmpSharedBoardSmsWrapper:source){ for(BlackNameListModel tmpBlackNameListModel:blackNameList){ if(tmpSharedBoardSmsWrapper.getSource().equals(tmpBlackNameListModel.getSource())){ source.remove(tmpSharedBoardSmsWrapper); break; } } }
異常簡略的成績!我竊笑,
測試…
令我不測的是,這段代碼竟然拋出了異常
java.util.ConcurrentModificationException。
檢查JDK6手冊
public class ConcurrentModificationException extends RuntimeException
當辦法檢測到對象的並發修正,但不許可這類修正時,拋出此異常。
例如,某個線程在 Collection 長進行迭代時,平日不許可另外一個線性修正該 Collection。平日在這些情形下,迭代的成果是不肯定的。假如檢測到這類行動,一些迭代器完成(包含 JRE 供給的一切通用 collection 完成)能夠選擇拋出此異常。履行該操作的迭代器稱為 疾速掉敗 迭代器,由於迭代器很快就完整掉敗,而不會冒著在未來某個時光隨意率性產生不肯定行動的風險。
留意,此異常不會一直指出對象曾經由 分歧 線程並發修正。假如單線程收回違背對象協議的辦法挪用序列,則該對象能夠拋出此異常。例如,假如線程應用疾速掉敗迭代器在 collection 上迭代時直接修正該 collection,則迭代器將拋出此異常。
留意,迭代器的疾速掉劣行為沒法獲得包管,由於普通來講,弗成能對能否湧現分歧步並發修正做出任何硬性包管。疾速掉敗操作會盡最年夜盡力拋出 ConcurrentModificationException
。是以,為進步此類操作的准確性而編寫一個依附於此異常的法式是毛病的做法,准確做法是: ConcurrentModificationException
應當僅用於檢測 bug。
Java中的For each
現實上應用的是iterator停止處置的。而iterator是不許可聚集在iterator應用時代刪除的。而我在for each
時,從聚集中刪除一個元素,這招致了iterator拋出了 ConcurrentModificationException
。
看來只要老誠實實應用傳統的for輪回了!
for(int i=0;i<source.size();i++){ SharedBoardSmsWrapper tmpSharedBoardSmsWrapper=source.get(i); for(int j=0;j<blackNameList.size();j++){ BlackNameListModel tmpBlackNameListModel=blackNameList.get(j); if(tmpSharedBoardSmsWrapper.getSource().equals(tmpBlackNameListModel.getSource())){ source.remove(tmpSharedBoardSmsWrapper); break; } } }
這下應當沒成績了吧!信念滿滿地按下測試…
暈!怎樣回事,數據怎樣過濾得纰謬?
Debug跟蹤後發明,本來,聚集刪除元素時,聚集的size會變小,連帶索引都邑轉變!
這可怎樣辦?我不會被如許一個小成績弄得沒轍了吧!
應用Iterator刪除聚集中的元素
檢查JDK手冊的Iterator接口,看到它還有一個remove辦法。
remove
void remove()
從迭代器指向的 collection 中移除迭代器前往的最初一個元素(可選操作)。每次挪用 next 只能挪用一次此辦法。假如停止迭代時用挪用此辦法以外的其他方法修正了該迭代器所指向的 collection,則迭代器的行動是不肯定的。
拋出:
UnsupportedOperationException
- 假如迭代器不支撐 remove 操作。
IllegalStateException
- 假如還沒有挪用 next 辦法,或許在上一次挪用 next 辦法以後曾經挪用了 remove 辦法。
准確的終究代碼:
/** *@paramsource *@paramblackNameList */ privatevoid screenBlackNameList(List<SharedBoardSmsWrapper> source, List<BlackNameListModel> blackNameList){ Iterator<SharedBoardSmsWrapper> sourceIt=source.iterator(); while(sourceIt.hasNext()){ SharedBoardSmsWrapper tmpSharedBoardSmsWrapper=sourceIt.next(); Iterator<BlackNameListModel> blackNameListIt=blackNameList.iterator(); while(blackNameListIt.hasNext()){ BlackNameListModel tmpBlackNameListModel=blackNameListIt.next(); if(tmpSharedBoardSmsWrapper.getSource().equals(tmpBlackNameListModel.getSource())){ sourceIt.remove(); break; } } } }
留意,一次Iterator的next()
辦法,不克不及屢次挪用remove()
辦法。不然會拋出異常。
看來,刪除聚集中的元素,最簡略的辦法,就是應用Iterator的remove()
辦法了!
讓我們看看ArrayList類供給的Iterator是如何完成的。
privateclass Itr implements Iterator<E> { /** 這是元素的索引,相當於一個指針,或許游標,應用它來拜訪List的數據元素。 *Indexofelementtobereturnedbysubsequentcalltonext. */ intcursor = 0; /** *Indexofelementreturnedbymostrecentcalltonextor *previous. Resetto-1ifthiselementisdeletedbyacall *toremove. 最新元素的索引。假如曾經刪除該元素,就設為-1 */ intlastRet = -1; /** 內部類ArrayList的屬性: protected transient int modCount = 0; 它用於不雅察ArrayList能否同時在被其他線程修正,假如紛歧致,那末就會拋出同步異常。 *ThemodCountvaluethattheiteratorbelievesthatthebacking *Listshouldhave. Ifthisexpectationisviolated,theiterator *hasdetectedconcurrentmodification. */ intexpectedModCount = modCount; //假如游標沒有到達List的尺寸,那末就還有元素。 publicboolean hasNext() { returncursor != size(); } //前往以後元素,然後游標+1。比來索引 也= 前往的元素的索引。 public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); thrownew NoSuchElementException(); } } /* 刪除元素,就是刪除以後元素,而且把游標-1。由於,List會把前面的元素全體移前一名。 */ publicvoid remove() { if (lastRet == -1) thrownew IllegalStateException(); checkForComodification(); try { AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { thrownew ConcurrentModificationException(); } } finalvoid checkForComodification() { if (modCount != expectedModCount) thrownew ConcurrentModificationException(); } }
總結
可以看到,Iterator刪除元素,而且把游標從新置為准確的位子。只需沒有其他線程同時轉變該聚集,就不會有任何成績。以上就是本文的全體內容了,願望對年夜家進修Java有所贊助。