我在Java中有TreeSet
,我有自己的比较器函数用于此树集。现在我使用descendingIterator()
方法遍历此树集并更改元素。那么这会更新实际树集以及使用我的自定义比较器排序的方式吗?或者我是否需要删除元素并放回更新的元素?
答案 0 :(得分:8)
您需要删除该元素并将其添加回来。通过将元素与其他元素进行比较,在插入元素时决定树中元素的位置。如果更改对象以便与其他元素进行比较更改,则必须先删除元素,然后更改它,然后重新添加。
请注意,在迭代时删除元素只能使用迭代器的remove方法。如果没有获得ConcurrentModificationException,AFAIK,您将无法在迭代期间添加它。因此,一旦迭代结束,将其存储在要重新添加到集合的元素列表中。
答案 1 :(得分:3)
如果修改作为“键”一部分的对象的任何部分(由自定义比较器定义),则需要删除并重新插入树集的对象以“学习”有关更改的内容。在迭代时你不应该这样做:一个好的方法是收集需要在一个循环中更改的项目,然后在另一个循环中修改并重新插入它们。
答案 2 :(得分:1)
作为一般的经验法则,不建议“修改”添加到依赖于相等,哈希码等的Java容器的任何值类型,因为没有任何已知的标准容器执行自动平衡或调整对价值变化的反应(这是有道理的)。
与Set
一起,此规则对Map
类型同样有效。如果您在地图上迭代并在原地修改“密钥”,那么事情就会变得糟糕。这就是为什么建议将不可变类型作为Map键的原因(考虑String
,Integer
等)。您的案例可以用一个简单的例子来证明:
public class Test {
public static void main(final String[] args) {
Mutable m1 = new Mutable(1);
Mutable m2 = new Mutable(2);
Mutable m3 = new Mutable(3);
Mutable m4 = new Mutable(4);
TreeSet<Mutable> ts = new TreeSet<Mutable>(new Cmp());
ts.add(m1); ts.add(m2); ts.add(m3); ts.add(m4);
System.out.println(ts);
for (Iterator<Mutable> iter = ts.iterator(); iter.hasNext(); ) {
Mutable m = iter.next();
if (m.i == 1 || m.i == 3) {
m.i = m.i + 10;
}
}
System.out.println(ts);
}
}
class Mutable {
public int i;
public Mutable(int i) {
this.i = i;
}
public String toString() {
return "Mutable[" + i + "]";
}
}
class Cmp implements Comparator<Mutable> {
@Override public int compare(Mutable o1, Mutable o2) {
return Integer.valueOf(o1.i).compareTo(Integer.valueOf(o2.i));
}
}
Output:
[Mutable[1], Mutable[2], Mutable[3], Mutable[4]]
[Mutable[11], Mutable[2], Mutable[13], Mutable[4]]