大佬教程收集整理的这篇文章主要介绍了java list.remove 适用于第一个元素,但不适用于其他元素 您如何在迭代期间实际删除项目?后续步骤,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
众所周知,不能在 foreach 中使用 List.remove。对我来说,阶段 1 运行正常但阶段 2 不是。有人可以解释一下吗?
第一阶段
List<String> List = new ArrayList<>();
List.add("1");
List.add("2");
for (String item : List) {
if ("1".equals(item)) {
List.remove(item);
}
}
System.out.println(List);
第二阶段
List<String> List = new ArrayList<>();
List.add("1");
List.add("2");
for (String item : List) {
if ("2".equals(item)) {
List.remove(item);
}
}
System.out.println(List);
疯了。你在java中发现了一个错误。如此简单的代码 - 令人难以置信。
请参考ArrayList的源码。错误是,具体来说,in ArrayList.java on line 962。
通常,数组列表有一个所谓的“mod counter”。任何时候您以任何方式修改数组列表(无论是添加、删除、清除等),modcounter 都会增加 1。
每当您调用 .iterator()
(for (String item :list)
一开始也执行一次)时,就会创建一个新的迭代器对象(请参阅上面链接中的第 947 行),并且该迭代器对象存储modcount 与创建迭代器时相同。
想法是所有迭代器方法(数量不多;只有 hasNext
、next
和 remove
)将首先检查后备数组列表(您通过调用其 .iterator()
方法从中获得迭代器的数组列表)与记住的 modcount 不同,如果是,迭代器将立即使用 ConcurrentModificationException
中止。
错误在于hasNext 方法无法做到这一点。我认为这是一个优化,但它导致了一个错误。
因此,发生了这种奇怪的交互:
List<String> list = new ArrayList<String>();
列表的 modcounter = 0。
list.add("1");
list.add("2");
@H_791_2@modcounter 现在是 2。
for (String item : list) {
if ("1".equals(item)) {
list.remove(item);
}
}
这是语法糖。 javac 编译它就好像它读:
Iterator<String> it$1 = list.iterator();
while (it$1.hasNext()) {
String item = it$1.next();
// your actual code inside the for loop here:
if ("1".equals(item)) {
list.remove(item);
}
}
所以让我们在此基础上进行讨论:
Iterator<String> it$1 = list.iterator();
一个迭代器对象制作完成;它的 expectedModCount
字段设置为 2
,因为这是 list
的当前 modcount。
while (it$1.hasNext()) {
迭代器的位置字段为0,后备列表的大小为2。所以,是的,还有更多的值要返回。 hasNext()
返回 true,进入 while 循环。
String item = it$1.next();
@H_791_2@modcounter 被检查。迭代器的expectedModCount
为2,列表的mod计数器为2,所以校验通过,item
设置为"1"
,迭代器的位置字段自增,即现在 1.
if ("1".equals(item)) {
list.remove(item);
}
该项确实是“1”,因此调用了 list.remove(item)
。 list 将其 modcount 更新为 3,将其大小更新为 1,并从其支持数组中删除 "1"
元素。
现在奇怪的事情接踵而至:
while (it$1.hasNext()) {
好吧,hasNext() 不会不检查迭代器的 expectedModCount
是否仍然等于列表的 @H_16_7@modCount。如果有,这将失败,但它不会那样做。迭代器的位置字段是1
,列表的大小也是1
,所以hasNext()
返回false,while循环退出。就是这样:我们在没有遇到 ConcurrentModificationException 的情况下就退出了循环。
相反,在第二个代码段中,您在 next()
上调用 it$1
两次,然后删除该元素。此时调用hasNext(),然后迭代器的position
字段为2,列表大小为1,具体检查(ArrayList的第962行)检查是否listSize != iteratorPosition
。因此,它不是,hasNext 返回 true(有点奇怪)。因此,while 循环第三次进入主体,运行 String item = it$1.next()
,而 next()
方法确实进行 modCount 检查。 expectedModCount
为 2,列表的 @H_16_7@modCount 为 3,因此 CoModEx 被抛出。
要重现这一点,您需要像这样删除数组列表中的倒数第二个元素。在您的 2 个元素的示例列表中,这将是第一个元素。
正确的策略是使用迭代器的 remove
方法。你不能在 for(:)
循环中访问迭代器,所以写:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String item = it.next();
if ("2".equals(item)) {
it.remove(); // this is how to do it!
}
}
remove() 在迭代器上是唯一的:假设 modcount 检查通过,它会增加迭代器的预期 modcount 以及支持列表的 mod 计数:这是在没有迭代器的情况下在迭代期间修改列表的唯一方法失败了(好吧,那个,还有你发现的这个错误)。
我会针对这个问题在 openjdk 提交一个错误。
以上是大佬教程为你收集整理的java list.remove 适用于第一个元素,但不适用于其他元素 您如何在迭代期间实际删除项目?后续步骤全部内容,希望文章能够帮你解决java list.remove 适用于第一个元素,但不适用于其他元素 您如何在迭代期间实际删除项目?后续步骤所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。