List集合删除元素的正确姿式详解

在阅读阿里巴巴规约的时候发现有一条规约是关于List的【不要在foreach里面进行元素的remove/add操做,remove请使用Iterator方式】。而后想起之前本身作项目的时候删除某一元素的逻辑报下标越界错误,那时候记得处理是用一新的List进行存储,而后总体从原List移除全部符合规则的元素,如今作一总结。用这个Iterator主要能够避免下标越界或者遍历是漏掉符合规则的下一个数据。java

先拉出来正确删除元素的姿式。正确姿式是利用Iterator的remove方法。具体操做以下:线程

public static void main(String[] args) {
        List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
        Iterator<Integer> iterator = lists.iterator();
        while (iterator.hasNext()){
            Integer obj = iterator.next();
            if(3==obj || 4==obj){
                iterator.remove();
            }
        }
        System.out.println(lists);
    }

而后经常使用的错误方式有如下三种: 
第一种方式,多出现下标越界问题。这个主要缘由是由于咱们在循环遍历时,将咱们的长度进行定值肯定。而忽略掉在知足条件时,list的长度是减小的。指针

public static void main(String[] args) {
 List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
        int size = lists.size();  // 定长设置,会形成元素下标越界,若是将for中变量直接换成lists.size()能够吗?
        for (int i = 0; i < size; i++) {
            if(3==lists.get(i) || 4 == lists.get(i)){
                lists.remove(i); //lists.remove(lists.get(i));
            }
        }
        System.out.println(lists);
 }

第二种方式也就是上面的注释所说,既然会出现下标越界,那我就利用动态的大小不就能够了,可是利用这种方法会产生另一种状况,就是会忽略掉remove元素后面的一个元素,这个是由于删除符合规则的元素后,list长度减一,而同时后面的元素往前补一位,形成当前i值下对应两个元素。code

public static void main(String[] args) {
        List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
        int size = lists.size();
        for (int i = 0; i < lists.size(); i++) {
            if(3==lists.get(i) || 4 == lists.get(i)){
                lists.remove(i); //lists.remove(lists.get(i));
            }
        }
        System.out.println(lists); // 打印[1, 2, 4, 5] 此时会将4忽略掉
    }

第三种方式是利用加强FOR循环形成的。这种方式会直接给报错:对象

ERRORInfo:
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)


public static void main(String[] args) {
        List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
       for (Integer i : lists){
           if(3==i || 4==i){
               lists.remove(i);
           }
       }
        System.out.println(lists);
    }

这种状况下。主要是集合遍历是使用Iterator, Iterator是工做在一个独立的线程中,而且拥有一个互斥锁。Iterator 被建立以后会创建一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,因此当索引指针日后移动的时候就找不到要迭代的对象,因此按照 fail-fast原则 Iterator 会立刻抛出java.util.ConcurrentModificationException 异常。因此 Iterator 在工做的时候是不容许被迭代的对象被改变的。索引

相关文章
相关标签/搜索