国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 實現Java刪除一個集合的多個元素

實現Java刪除一個集合的多個元素

2020-06-02 11:06java教程網 JAVA教程

Java中的For each實際上使用的是iterator進行處理的。而iterator是不允許集合在iterator使用期間刪除的。而我在for each時,從集合中刪除了一個元素,這導致了iterator拋出了ConcurrentModificationException,下面來看看到底怎么回事。

問題

我需要從一個java的集合中,根據另一個集合的內容,刪除第一個集合中不特定的元素。這看上去非常簡單,但卻遇到了問題。

這是我要寫的方法的頭部

?
1
private void screenBlackNameList(List<SharedBoardSmsWrapper> source, List<BlackNameListModel> blackNameList)

事情是這樣子的。source集合中保存了一些顯示用的數據元素。blackNameList集合中保存的是黑名單列表。我們需要根據黑名單表,把source集合中黑名單用戶的數據剔除掉。

這個問題的解決看上去非常簡單。

我首先使用for each 語句進行刪除。

?
1
2
3
4
5
6
7
8
9
10
for(SharedBoardSmsWrapper tmpSharedBoardSmsWrapper:source){
 
    for(BlackNameListModel tmpBlackNameListModel:blackNameList){
      if(tmpSharedBoardSmsWrapper.getSource().equals(tmpBlackNameListModel.getSource())){
        source.remove(tmpSharedBoardSmsWrapper);
        break;
      }
 
    }
  }

非常簡單的問題!我暗笑,

測試…

令我意外的是,這段代碼居然拋出了異常

java.util.ConcurrentModificationException。

查看JDK6手冊

?
1
2
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循環了!

?
1
2
3
4
5
6
7
8
9
10
11
12
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

?
1
void remove()

從迭代器指向的 collection 中移除迭代器返回的最后一個元素(可選操作)。每次調用 next 只能調用一次此方法。如果進行迭代時用調用此方法之外的其他方式修改了該迭代器所指向的 collection,則迭代器的行為是不確定的。

拋出:

UnsupportedOperationException - 如果迭代器不支持  remove 操作。

IllegalStateException - 如果尚未調用  next 方法,或者在上一次調用  next 方法之后已經調用了  remove 方法。

正確的最終代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
   *@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;
      }
 
    }
 
  }
 
  }

注意,一次Iteratornext()方法,不能多次調用remove()方法。否則會拋出異常。

看來,刪除集合中的元素,最簡單的方法,就是使用Iteratorremove()方法了!

讓我們看看ArrayList類提供的Iterator是怎樣實現的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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有所幫助。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日韩精品中文字幕在线 | 久久先锋 | 午夜在线影院 | 国产中文视频 | 久久精彩视频 | 日韩av在线一区 | 久久精彩免费视频 | 黄色大片aaaa | 日本久久综合 | 99精品国产一区二区三区 | 午夜精品一区二区三区在线视频 | 亚洲精品区 | 91电影在线 | 中文字幕亚洲欧美日韩在线不卡 | 看av网站 | 日本在线中文 | 国产综合亚洲精品一区二 | 亚洲欧美自拍视频 | 99riav在线 | 1区2区在线观看 | 久久精品综合 | 国产精品久久免费观看spa | a国产精品 | 精品美女一区 | 日韩精品免费一区二区三区 | 国产xnxx| 日韩视频在线观看 | 久久精品一区二区三区四区 | 久久影视精品 | 国产精品久久嫩一区二区免费 | 国产精品高清在线 | 青草福利 | 日韩电影一区二区在线观看 | 欧美色欧美亚洲另类七区 | 亚洲视频欧美视频 | 一呦二呦三呦国产精品 | 91综合在线| 久久精品一区二区 | 亚洲免费视频一区 | 国产成人精品亚洲日本在线观看 | 狠久久|