zoukankan      html  css  js  c++  java
  • 注意了!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、后端、架构、阿里巴巴等大厂最新面试题

    生活很美好,明天见~

  • 相关阅读:
    poj1862---变形虫(贪心)
    poj1833---字典序算法
    poj1799---解析几何
    poj1665
    poj1663---纯粹找规律
    poj1658
    poj1657---chessboard
    poj1656---数黑格子
    poj1617---columnar encryption
    查找两个文件的相同之处,不同之处
  • 原文地址:https://www.cnblogs.com/javastack/p/12515934.html
Copyright © 2011-2022 走看看