java基础--ArrayList循环遍历删除指定元素时的陷阱

最近,在参加面试的时候遇到考官问这样一个问题,在ArrayList循环遍历的时候删除指定元素是否会出现报错的情况,之前对这个问题没有太过关注,所以回答情况不太理想。后来自己回来研究了一下,发现确实在遍历数组时进行删除存在一些陷阱,废话不多说,直接贴上实践总结代码:

for遍历时删除元素的陷阱

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

/**
 * @author yanzy
 * @Description ArrayList循环遍历删除元素陷阱--for循环中出现的错误场景分析
 * @date 2018-06-22 11:29
 */
public class RemoveByFor {
    //ArrayList中fastremove方法执行的操作为数组本身替换,
    // 用 删除元素的位置后移一位到原数组结尾位置的内容 替换 删除元素的位置到原数组结尾位置前移一位的内容,
    // 最后将数组最后一位设置为null
    private List<String> list;

    public RemoveByFor(List<String> list){
        this.list = list;
    }
    //错误1:for循环删除ArrayList中的指定值对象,如下写法ArrayList中"bb"只删除了一个,未全部删除
    //
    //原因:
    //由上述可知,删除指定元素最终用到的方法为fastremove,它的实现原理为位置移动,在此处错误场景中,
    // 执行第二个元素"bb"删除后,第三个元素"bb"位置前移了一位,
    // 在执行循环的下一次操作时,处理的第三个元素为之前的第四位,跳过了对原数组第三个元素"bb"的操作,
    // 所以会产生"bb"未删除干净的错误
    //
    //解决方案:
    //倒序遍历进行删除,倒序遍历时,由于删除后数组对象移动的方向与循环遍历操作的方向一致,所以删除操作不会对结果产生影响

    /****错误方法****/
    public void errorRemove(String deleteVal){
        for(int i = 0;i < list.size()-1;i++) {
            if(list.get(i).equals(deleteVal)){
                list.remove(list.get(i));
            }
        }
        ListIterator listIterator = list.listIterator();
        while(listIterator.hasNext()){
            System.out.println("---------------------------\t\n");
            System.out.println(listIterator.next() + "\t\n");
        }
    }

    /****正确方法****/
    public void correctRemove(String deleteVal){
        for(int i = list.size()-1;i >= 0;i--) {
            if(list.get(i).equals(deleteVal)){
                list.remove(list.get(i));
            }
        }
        ListIterator listIterator = list.listIterator();
        while(listIterator.hasNext()){
            System.out.println("---------------------------\t\n");
            System.out.println(listIterator.next() + "\t\n");
        }
    }

    public static void main(String[] args) {

        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("bb");
        list.add("bb");
        list.add("ccc");
        list.add("ccc");
        list.add("ccc");

        RemoveByFor removeByFor = new RemoveByFor(list);
        //removeByFor.errorRemove("bb");
        removeByFor.correctRemove("bb");


    }
}

上述代码,失败情景返回结果:

--------------------------- 

a   

--------------------------- 

bb  

--------------------------- 

ccc 

--------------------------- 

ccc 

--------------------------- 

ccc 

成功情况,返回结果:

--------------------------- 

a   

--------------------------- 

bb  

--------------------------- 

ccc 

--------------------------- 

ccc 

--------------------------- 

ccc 

foreach增强遍历时删除元素的陷阱

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/**
 * @author yanzy
 * @Description ArrayList循环遍历删除元素陷阱--foreach循环中出现的错误场景分析
 * @date 2018-06-22 13:09
 */
public class RemoveByForeach {
    //fastremove方法中,将记录修改数的变量值modCount进行了+1操作,
    //ArrayList继承自父类的iterator方法返回的迭代器中的next方法实现中首先进行的操作就是检查迭代器内部修改次数
    //checkForComodification(),而ConcurrentModificationException正是在此方法中返回的
    //判断条件为modCount != expectedModCount

    private List<String> list;

    public RemoveByForeach(List<String> list) {
        this.list = list;
    }

    //错误2:foreach循环删除ArrayList中的指定值对象,如下写法出现java.util.ConcurrentModificationException异常
    //
    //原因:
    //由上述可知,ArrayList的remove方法调用的时候会修改modCount值,,触发iterator的fast-fail机制,故出现该异常
    //
    //解决方案:
    //直接使用Iterator中的remove方法进行删除

    /****错误方法****/
    private void errorRemove(String deleteVal) {
        for (String val : list) {
            if (val.equals(deleteVal)) {
                list.remove(val);
            }
        }
        ListIterator listIterator = list.listIterator();
        while(listIterator.hasNext()){
            System.out.println("---------------------------\t\n");
            System.out.println(listIterator.next() + "\t\n");
        }
    }

    private void correctRemove(String deleteVal){
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            if(iterator.next().equals(deleteVal)){
                iterator.remove();
            }
        }
        ListIterator listIterator = list.listIterator();
        while(listIterator.hasNext()){
            System.out.println("---------------------------\t\n");
            System.out.println(listIterator.next() + "\t\n");
        }
    }

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("bb");
        list.add("bb");
        list.add("ccc");
        list.add("ccc");
        list.add("ccc");

        RemoveByForeach removeByForeach = new RemoveByForeach(list);
        removeByForeach.errorRemove("bb");
        //removeByForeach.correctRemove("bb");


    }
}

上述代码,失败情况返回结果:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
    at java.util.AbstractList$Itr.next(AbstractList.java:343)
    at web.action.RemoveByForeach.errorRemove(RemoveByForeach.java:35)
    at web.action.RemoveByForeach.main(RemoveByForeach.java:71)

成功情况返回结果:

--------------------------- 

a   

--------------------------- 

ccc 

--------------------------- 

ccc 

--------------------------- 

ccc 

猜你喜欢

转载自blog.csdn.net/yzy199391/article/details/80776660