Java列表';s.remove方法只对每个循环中最后一个对象起作用
我看到一种奇怪的行为Java列表';s.remove方法只对每个循环中最后一个对象起作用,java,foreach,Java,Foreach,我看到一种奇怪的行为 List<String> li = new ArrayList<>(); li.add("a"); li.add("b"); li.add("c"); li.add("d"); li.add("e"); for(String str:li){ if(str.equalsIgnoreCase("d")){ li.remove(str); //remo
List<String> li = new ArrayList<>();
li.add("a");
li.add("b");
li.add("c");
li.add("d");
li.add("e");
for(String str:li){
if(str.equalsIgnoreCase("d")){
li.remove(str); //removing second last in list works fine
}
}
List li=new ArrayList();
li.添加(“a”);
li.添加(“b”);
li.添加(“c”);
li.添加(“d”);
li.添加(“e”);
用于(字符串str:li){
if(str.equalsIgnoreCase(“d”)){
li.remove(str);//删除列表中的倒数第二个很好
}
}
但如果我尝试删除列表中除倒数第二个之外的任何一个,就会得到ConcurrentModificationException。我在阅读《Oracle认证助理Java SE 7程序员学习指南2012》时注意到了这一点,该指南错误地假设.remove()总是与删除列表中最后一个的示例一起使用。请在循环时从列表中删除元素时使用迭代器#remove()
方法。在内部,每个
循环的将使用迭代器
在列表
中循环,因为如果在迭代过程中以除调用迭代器的remove()以外的任何方式修改基础集合,迭代器
的行为是未指定的方法。您将获得异常
此循环:
for(String str:li){
if(str.equalsIgnoreCase("d")){
li.remove(str); //removing second last in list works fine
}
}
基本上
Iterator<String> itr = li.iterator();
while(itr.hasNext()){
String str = (String)itr.next();
if(str.equalsIgnoreCase("d")){
li.remove(str); //removing second last in list works fine
}
}
因此,在这种情况下,cursor=size=4
,因此hasNext()
的计算结果为false
,循环在next()
中执行并发修改检查之前提前中断。在这种情况下,永远不会访问最后一个元素。如果
if(str.equalsIgnoreCase("d") || str.equalsIgnoreCase("e")){
// last element "e" won't be removed as it is not accessed
li.remove(str);
}
但是,如果您删除任何其他元素next()
,则会调用该元素,从而引发ConcurrentModificationException
请不要在此处使用List#删除(对象)
,因为您正在为每个循环访问列表中的元素
改为使用从列表中删除项目:
for(Iterator<String> it=li.iterator(); it.hasNext();) {
String str = it.next();
if(str.equalsIgnoreCase("d")) {
it.remove(); //removing second last in list works fine
}
}
for(Iterator it=li.Iterator();it.hasNext();){
String str=it.next();
if(str.equalsIgnoreCase(“d”)){
it.remove();//删除列表中的倒数第二个很好
}
}
由于ArrayList的fail fast行为引发ConcurrentException。这意味着,除了迭代器#remove()
参考如果你真的想在
数组列表上迭代并删除元素,那么你应该这样做:
for(int index = yourArrayList.size() - 1; index >= 0; index--) {
if(yourCondition) {
yourArrayList.remove(index);
}
}
您可以“向后”迭代并删除元素,但不能向前。因此,与其从第一个元素迭代到最后一个元素,不如从最后一个元素迭代到第一个元素
伪代码:
for(int i = list.size() -1; i >= 0; i--)
{
list.remove(i);
}
在列表中,添加或删除被视为修改。在你的情况下,你做了
5修改(增补)
“for each”循环的工作原理如下:
3.如果为true,则使用next()获取下一个元素
重复步骤2和3,直到hasNext()返回false
如果我们从列表中删除一个元素,它的大小会减小,modCount会增加
如果我们在迭代时删除一个元素,modCount!=期望的模块数量得到满足
并抛出ConcurrentModificationException
但移除倒数第二个物体很奇怪。让我们看看它在您的案例中是如何工作的
最初,
游标=0 size=5-->hasNext()成功,next()也成功
毫无例外。
游标=1 size=5-->hasNext()成功,next()也成功
毫无例外。
游标=2 size=5-->hasNext()成功,next()也成功
毫无例外。
游标=3 size=5-->hasNext()成功,next()也成功
毫无例外
在您的情况下,当您删除“d”时,大小将减少到4
cursor=4 size=4-->hasNext()未成功,而next()未成功
跳过
在其他情况下,ConcurrentModificationException将作为modCount!抛出预期的模数
在这种情况下,不会进行此检查
如果在迭代时尝试打印元素,则只会打印四个条目。跳过最后一个元素
希望我说得清楚。如果你想删除所有,那么。removeAll应该做到这一点,而不是遍历集合。我认为它也更快 实际上我知道如何删除数组中的一个元素,但我想指出为什么它只对最后一个元素起作用,这是一个错误吗??
for(int i = list.size() -1; i >= 0; i--)
{
list.remove(i);
}
1.It gets the iterator.
2.Checks for hasNext().
public boolean hasNext()
{
return cursor != size(); // cursor is zero initially.
}
public E next()
{
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
final void checkForComodification()
{
// Initially modCount = expectedModCount (our case 5)
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}