注意了!ArrayList 增删千万不要乱用…

2020-03-18 09:24:44来源:博客园 阅读 ()

容器云强势上线!快速搭建集群,上万Linux镜像随意使用

注意了!ArrayList 增删千万不要乱用…

编程过程中常常需要使用到集合,而ArrayList是我们常常使用的,但是最近在一次删除和增加中出现了一些问题,分享记录下。

分下如下俩段代码

List<String>?arrayList1?=?new?ArrayList<String>();
arrayList1.add("1");
arrayList1.add("2");
for?(String?s?:?arrayList1)?{
    if("1".equals(s)){
?       arrayList1.remove(s);
?   }}
    List<String>?arrayList2?=?new?ArrayList<String>();
    arrayList2.add("2");arrayList2.add("1");
    for?(String?s?:?arrayList2)?{
?       if("1".equals(s)){
?       arrayList2.remove(s);
?   }
}

程序运行结果如下:

arrayList1的remove方法成功执行,
arrayList2的remove方法运行抛出ConcurrentModificationException异常。

我们查看源代码来分析异常原因
因为foreach的本质就是使用迭代器Iterator,所有的Collecation集合类都会实现Iterable接口。
找到ArrayList类的iterator()方法

public?Iterator<E>?iterator()?{
    return?new?Itr();
}

迭代器的本质是先调用hasNext()方法判断存不存在下一元素,然后再使用next()方法取下一元素

public?boolean?hasNext()?{
    return?cursor?!=?size;
}

@SuppressWarnings("unchecked")
public?E?next()?{
????checkForComodification();
????int?i?=?cursor;
????if?(i?>=?size)
????????throw?new?NoSuchElementException();
????Object\[\]?elementData?=?ArrayList.this.elementData;
????if?(i?>=?elementData.length)
????????throw?new?ConcurrentModificationException();
????cursor?=?i?+?1;
????return?(E)?elementData\[lastRet?=?i\];
}

上面arraylist1为什么能remove成功呢?其实它只循环了一次,所以成功了。

因为它在remove元素1之后,它的size-1变成1,然后Itr内部的cursor变量由0变成1,此时1=1,循环结束,所以成功了。

arraylist2为什么remove失败呢?因为它在循环第二次的时候,也remove成功了,但是第三次判断next的时候cursor的值为2导致不等于现在的size 1,所以执行了next方法,最重要的来了,之前remove的操作导致ArrayList的modCount值加1,然后Itr类中的expectedModCount保持不变,所以会抛出异常。

final?void?checkForComodification()?{
    if?(modCount?!=?expectedModCount)
        throw?new?ConcurrentModificationException();
}

同理可得,由于add操作也会导致modCount自增,所以不允许在foreach中删除, 增加,修改ArrayList中的元素。

对此,推荐大家使用迭代器Iterator删除元素。

Iterator<String>?ite?=?arrayList2.iterator();
while(ite.hasNext())?{
    if("1".equals(ite.next()))?{
        ite.remove();
    }
}

如果存在并发操作,还需要对Iterator进行加锁操作。

作者:奋斗的小程序员
https://www.toutiao.com/i6754322606561690116/

推荐去我的博客阅读更多:

1.Java JVM、集合、多线程、新特性系列教程

2.Spring MVC、Spring Boot、Spring Cloud 系列教程

3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程

4.Java、后端、架构、阿里巴巴等大厂最新面试题

生活很美好,明天见~


原文链接:https://www.cnblogs.com/javastack/p/12515934.html
如有疑问请与原作者联系

标签:操作forAV编程gitHTTP

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:IntelliJ IDEA 2019.3注册码直接激活免Host和Agent 每日更新

下一篇:Java 创建、编辑、删除Excel命名区域