抽象设置不同的逻辑
AbstractSet different logic
在 AbstractSet.removeAll() 中有两个代码将集标记为已修改。
抽象集是
public boolean removeAll(Collection<?> c) {
boolean modified = false;
if (size() > c.size()) {
for (Iterator<?> i = c.iterator(); i.hasNext(); )
modified |= remove(i.next()); //1
} else {
for (Iterator<?> i = iterator(); i.hasNext(); ) {
if (c.contains(i.next())) {
i.remove(); //2
modified = true; //2
}
}
}
return modified;
}
第二个 (//2) 不同于第一个 (//1) modified |= remove(i.next());
背后的逻辑是什么?
我会将第二个 (//2) 重写为与第一个 (//1) 相同,以免进行额外检查 (contains(i.next())
)。
public boolean removeAll(Collection<?> c) {
boolean modified = false;
if (size() > c.size()) {
for (Iterator<?> i = c.iterator(); i.hasNext(); )
modified |= remove(i.next()); //1
} else {
for (Iterator<?> i = iterator(); i.hasNext(); ) {
i.next();
modified |= i.remove()); //2
}
}
return modified;
}
Update1: i.remove()
returns 无效。
Update2: i.remove() 将清空不受欢迎结果的集合。
基于update1,update2这个重写是行不通的。
在遍历 Collection
(调用 removeAll
的 Set
)中安全删除元素的唯一方法是使用 Iterator
s remove
方法。使用 remove(i.next())
将抛出 ConcurrentModificationException
.
另一方面,第一个循环不会遍历要从中删除元素的 Set
(它遍历作为参数传递的 Collection
)。因此remove(i.next())
可以安全调用。
这两个循环的另一个区别是,在第一个循环中,remove(i.next())
不能保证从 Set
中删除任何内容(因为要删除的元素可能不在 Set
),因此您想对 remove
调用的所有结果进行或运算以确定是否删除了任何内容。这就是 modified |= remove(i.next());
.
的原因
另一方面,当使用 Iterator
的删除时,您肯定知道一个元素已被删除(这可能是 Iterator
的删除没有 return 任何东西 - 如果有,它总是 return true
) 所以你可以在删除第一个元素后简单地将 modified
设置为 true
。
编辑:
关于您的编辑,建议重写第二个循环以删除 contains(i.next())
检查 - 甚至忽略 modified |= i.remove())
中的编译错误(由 [= 的 void return 类型导致13=] 的删除),这将清空 Set
而不是仅删除 Set
.
中存在的 c
的元素
第一个调用使用 Set.remove(),第二个调用 Iterator.remove()。
要点是:第一个 return 一个布尔值,因此 "final" 结果可以通过 "or'ing" 调用 set.remove( ).
而第二个 iterator.remove() 没有 return 任何东西 - 它是一个无效的方法!因此,您需要一种不同的方法来 "compute" 那个布尔值!
在 AbstractSet.removeAll() 中有两个代码将集标记为已修改。
抽象集是
public boolean removeAll(Collection<?> c) {
boolean modified = false;
if (size() > c.size()) {
for (Iterator<?> i = c.iterator(); i.hasNext(); )
modified |= remove(i.next()); //1
} else {
for (Iterator<?> i = iterator(); i.hasNext(); ) {
if (c.contains(i.next())) {
i.remove(); //2
modified = true; //2
}
}
}
return modified;
}
第二个 (//2) 不同于第一个 (//1) modified |= remove(i.next());
背后的逻辑是什么?
我会将第二个 (//2) 重写为与第一个 (//1) 相同,以免进行额外检查 (contains(i.next())
)。
public boolean removeAll(Collection<?> c) {
boolean modified = false;
if (size() > c.size()) {
for (Iterator<?> i = c.iterator(); i.hasNext(); )
modified |= remove(i.next()); //1
} else {
for (Iterator<?> i = iterator(); i.hasNext(); ) {
i.next();
modified |= i.remove()); //2
}
}
return modified;
}
Update1: i.remove()
returns 无效。
Update2: i.remove() 将清空不受欢迎结果的集合。
基于update1,update2这个重写是行不通的。
在遍历 Collection
(调用 removeAll
的 Set
)中安全删除元素的唯一方法是使用 Iterator
s remove
方法。使用 remove(i.next())
将抛出 ConcurrentModificationException
.
另一方面,第一个循环不会遍历要从中删除元素的 Set
(它遍历作为参数传递的 Collection
)。因此remove(i.next())
可以安全调用。
这两个循环的另一个区别是,在第一个循环中,remove(i.next())
不能保证从 Set
中删除任何内容(因为要删除的元素可能不在 Set
),因此您想对 remove
调用的所有结果进行或运算以确定是否删除了任何内容。这就是 modified |= remove(i.next());
.
另一方面,当使用 Iterator
的删除时,您肯定知道一个元素已被删除(这可能是 Iterator
的删除没有 return 任何东西 - 如果有,它总是 return true
) 所以你可以在删除第一个元素后简单地将 modified
设置为 true
。
编辑:
关于您的编辑,建议重写第二个循环以删除 contains(i.next())
检查 - 甚至忽略 modified |= i.remove())
中的编译错误(由 [= 的 void return 类型导致13=] 的删除),这将清空 Set
而不是仅删除 Set
.
c
的元素
第一个调用使用 Set.remove(),第二个调用 Iterator.remove()。
要点是:第一个 return 一个布尔值,因此 "final" 结果可以通过 "or'ing" 调用 set.remove( ).
而第二个 iterator.remove() 没有 return 任何东西 - 它是一个无效的方法!因此,您需要一种不同的方法来 "compute" 那个布尔值!