2015-07-13 37 views
3

TreeSet(一SortedSet)在Java中8:SortedSet :: removeAll(headSet)失敗,但從headSet派生另一個集合成功。爲什麼?

  1. 我稱之爲::headSet方法在排序集合的前面,以獲得對象的SortedSet
  2. 我打電話給::removeAll刪除那些最前面的對象。
    BAM,拋出一個ConcurrentModificationException

然而,如果我從headSet製作另一個SortedSet並將派生集合傳遞給::removeAll,沒有問題。

爲什麼?

使用Java 8更新的演示代碼45.啓用行//sortedSet.removeAll(headSet);以查看引發的異常。

String cockatiel = "Cockatiel"; 

SortedSet sortedSet = new TreeSet<String>(); 
sortedSet.add("Dog"); 
sortedSet.add("Cat"); 
sortedSet.add("Bird"); 
sortedSet.add("Elephant"); 
sortedSet.add(cockatiel); // Passing var rather than literal. 
sortedSet.add("Guppy"); 

System.out.println("Before: " + sortedSet); 

// Direct way. FAIL 
SortedSet<String> headSet = sortedSet.headSet(cockatiel); 
System.out.println("headSet: " + headSet); 
//sortedSet.removeAll(headSet); // Fails. Throws java.util.ConcurrentModificationException. 

// Derived way. PASS 
SortedSet<String> headSetDerived = new TreeSet<String>(headSet); // Make a TreeSet from a TreeSet. 
sortedSet.removeAll(headSetDerived); // Succeeds. Why? 

System.out.println("After: " + sortedSet); 

回答

3

耳機背靠原始設置

在第一個方法,你正在修改的設置(刪除元素)超過它在同一時間迭代(獲取元素刪除)。這拋出了異常。請記住,頭部集合由原始集合支持,因此修改原始集合最終會修改頭部集合 - 在迭代該頭部集合時無法完成。

TreeSet::headSet DOC(粗體是我的重點)摘錄:

返回set的部分視圖 ...。 返回集由此集支持,因此返回集中的更改反映在此集中,反之亦然。

解決辦法

通常有兩種方法來解決這個問題。一種是直接使用迭代器並使用其方法remove()。另一種是通過第一次迭代來分離迭代和修改,以創建該集合的副本,然後迭代該副本以從原始中移除;這是你在第二種方法中所做的。

+0

我沒有意識到headSet是由原始Set支持的。我現在在文檔中看到。這解釋了這種行爲,其中第一次刪除成功,而進一步刪除引發異常。謝謝。 –

相關問題