枚举是故障安全的。故障安全迭代器将用于克隆原始集合。那么为什么它会抛出concurrentModificationException?请澄清。
请找到我的代码:
public static void main(String[] args) {
Vector<String> v=new Vector<String>();
v.add("Amit");
v.add("Raj");
v.add("Pathak");
v.add("Sumit");
v.add("Aron");
v.add("Trek");
Enumeration en=(Enumeration) Collections.enumeration(v);
while(en.hasMoreElements())
{
String value=(String) en.nextElement();
System.out.println(value);
v.remove(value);//modifying the collection
}
}
找到下面的错误消息
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.Vector$Itr.checkForComodification(Unknown Source)
at java.util.Vector$Itr.next(Unknown Source)
at java.util.Collections$2.nextElement(Unknown Source)
at valar.org.src.EnumerationTest.main(EnumerationTest.java:24)
答案 0 :(得分:2)
Collections.enumeration(Collection)
将从作为参数传递的集合中创建一个迭代器:
public static <T> Enumeration<T> enumeration(final Collection<T> c) {
return new Enumeration<T>() {
private final Iterator<T> i = c.iterator();
public boolean hasMoreElements() {
return i.hasNext();
}
public T nextElement() {
return i.next();
}
};
}
这意味着迭代器被支持到你在迭代器循环中删除元素的集合,你不能删除使用迭代器迭代的集合的元素。
您应该在Vector
调用中创建enumeration()
的副本:
Enumeration<String> en = Collections.enumeration(new Vector<String>(v));
作为旁注,您应该支持List
接口和ArrayList
实现Vector
(已同步)并声明备用转换,并增加类型的安全性代码。
所以它会给出这个代码(我离开Vector
使用,因为它可能是一个不可修改的约束,但我指定了泛型,因为它甚至在遗留代码中添加通常更简单):
Vector<String> v = new Vector<String>();
v.add("Amit");
v.add("Raj");
v.add("Pathak");
v.add("Sumit");
v.add("Aron");
v.add("Trek");
Enumeration<String> en = Collections.enumeration(new Vector<String>(v));
while (en.hasMoreElements()) {
String value = (String) en.nextElement();
System.out.println(value);
v.remove(value);// modifying the collection
}
答案 1 :(得分:1)
您的枚举在内部使用Iterator。迭代元素时,不能使用向量本身来删除项目。你必须使用迭代器。但是你无法访问它。改为创建一个迭代器:
public static void main(String[] args) {
final Vector<String> v = new Vector<String>();
v.add("Amit");
v.add("Raj");
// Use an Iterator to remove the value you are iterating over
final Iterator<String> iterator = v.iterator();
while (iterator.hasNext()) {
final String value = iterator.next();
System.out.println(value);
iterator.remove();
}
}
尽管Vector实际上已经被弃用了。您应该改为使用List:
正确列表的导入(不要使用awt.List):
import java.util.ArrayList;
import java.util.List;
更改后的代码:
public static void main(String[] args) {
final List<String> v = new ArrayList<>();
v.add("Amit");
v.add("Raj");
v.add("Pathak");
final Iterator<String> iterator = v.iterator();
while (iterator.hasNext()) {
final String value = iterator.next();
System.out.println(value);
iterator.remove();
}
}
另请注意,您可以将接口用作Type,这通常是使用该实现的首选。
编辑:
看看你的例子,也许你真正需要的是一个队列:
public static void main(String[] args) {
final Queue<String> v = new LinkedList<>();
v.add("Amit");
v.add("Raj");
v.add("Pathak");
System.out.println("Size: " + v.size());
for (String element = v.poll(); element != null; element = v.poll()) {
System.out.println(element);
}
System.out.println("Size: " + v.size());
}
输出:
Size: 3
Amit
Raj
Pathak
Size: 0
这与您的示例相同。有关收藏集的详细信息,请参阅The official Collections Java Trail
答案 2 :(得分:0)
枚举是故障安全的。
正确。 (允许一些语言困难。)
故障安全迭代器将用于克隆原始集合。
正确。 (允许一些语言困难。)
那为什么它会抛出concurrentModificationException?
因为没有涉及克隆。
克隆在哪里?
答案 3 :(得分:0)
你正在使用不支持删除方法的Enumeration。一旦你创建了一个Enumeration,它就会测试checkForComodification。所以当你从向量中删除时,modCount会增加,而且expectModCount也不会被修改。
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
请使用迭代器修改您的代码
public static void main(String[] args) {
Vector<String> v = new Vector<String>();
v.add("Amit");
v.add("Raj");
v.add("Pathak");
v.add("Sumit");
v.add("Aron");
v.add("Trek");
Iterator<String> it =v.iterator();
while (it.hasNext()) {
String value = it.next();
System.out.println(value);
it.remove();
}
}