2015-07-13 72 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支持的。我现在在文档中看到。这解释了这种行为,其中第一次删除成功,而进一步删除引发异常。谢谢。 –

相关问题