- 问题及分析
- 正确删除集合元素
【Java|Java 遍历集合删除元素()】先写开发手册里一个例子,大家猜一下以下代码的输出
List list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
System.out.println("list original size is " + list.size());
for (String item : list) {
if ("1".equals(item)) {
list.remove(item);
}
}System.out.println("list size is " + list.size());
List list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
System.out.println("list original size is " + list.size());
for (String item : list) {
if ("1".equals(item)) {
list.remove(item);
}
}System.out.println("list size is " + list.size());
上面两个例子的输出结果是什么?意外吗?
1,2可以成功;1, 2, 3删除抛出异常
- 第一个:
list original size is 2
list size is 1 - 第二个:
list original size is 3
java.util.ConcurrentModificationException
List list = new ArrayList();
list.add("1");
list.add("2");
// list.add("3");
System.out.println("list original size is " + list.size());
Iterator var2 = list.iterator();
while(var2.hasNext()) {
String item = (String)var2.next();
if ("1".equals(item)) {
list.remove(item);
}
}System.out.println("list size is " + list.size());
通过查看反编译代码,发现我们使用的foreach遍历仍然是迭代器Iterator遍历,而ArrayList中Iterator源码:
private class Itr implements Iterator {
int cursor;
// index of next element to return
int lastRet = -1;
// index of last element returned;
-1 if no such
int expectedModCount = modCount;
Itr() {}public boolean hasNext() {
return cursor != size;
// 游标
}@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
// 检查是否并发修改
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = https://www.it610.com/article/ArrayList.this.elementData;
if (i>= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
// 游标后移
return (E) elementData[lastRet = i];
}public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
// 修改预期值(迭代器删除的重要参考)
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
......
}
modCount是集合添加,删除等改变集合结构的次数(改变集合大小),expectedModCount是预期的变化次数;
分析一下:
[“1”, “2”] : 当”1”被遍历删除后,游标cursor的值从0变为1,集合长度也变为1,这是hasNext返回false,比较表示没有下一个元素,结束遍历;
[“1”, “2”, “3”] : 如上,当”1”遍历删除后,游标cursor从0变为1,集合长度变为2,hasNext返回true,执行remove时,checkForComodification()方法验证是否同时修改,此方法表modCount != expectedModCount,modCount是3,expectedModCount也是3,而在删除后modCount变为4,而hasNext()方法不返回false,next()方法调用时就会抛出异常;
注:由其游标变化规律可以看出,如果hasNext提前结束,不执行后面的next取数据,就可以删除集合元素,故可以删除集合中倒数第二个元素而不抛出异常(实践也如此)
正确删除集合元素
- 迭代器方式
public void positiveForEachTest() {
List list = new ArrayList<>();
list.add("w");
list.add("li");
list.add("z");
System.out.println("list original size is " + list.size());
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if ("li".equals(item)) {
iterator.remove();
}
}System.out.println("after list remove elem `li`, it's size is " + list.size());
}
推荐阅读
- Java|Java基础——数组
- 人工智能|干货!人体姿态估计与运动预测
- java简介|Java是什么(Java能用来干什么?)
- Java|规范的打印日志
- Linux|109 个实用 shell 脚本
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- JavaScript|JavaScript: BOM对象 和 DOM 对象的增删改查
- Spring注解驱动第十讲--@Autowired使用
- SqlServer|sql server的UPDLOCK、HOLDLOCK试验
- jvm|【JVM】JVM08(java内存模型解析[JMM])