List集合删除元素的正确姿势

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

先拉出来正确删除元素的姿势。正确姿势是利用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);

    }

附上自己比较笨的操作方式:

public static void main(String[] args){
            List<Integer> lists = new ArrayList<Integer>();
            List<Integer> listscopy = new ArrayList<>();
            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)){
                    listscopy.add(lists.get(i));
                }
            }
            lists.removeAll(listscopy);
            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值下对应两个元素。

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 在工作的时候是不允许被迭代的对象被改变的。

【 文章有查询:高爽|Coder,原文地址:http://blog.youkuaiyun.com/ghsau/article/details/9347357。】

任务描述 本关任务:定义四种开发中常用的集合并添加数据。 相关知识 为了完成本关任务,你需要掌握: 1.集合的体系结构; 2.如何创建常见的集合。 在前两个关卡中我们学习的ArrayList集合只是集合的一个部分,Java中的集合可没那么简单呢,Java中的集合是一个大家族,接下来我们就来见识一下这个家族吧。 集合的体系结构 Java中的集合分为两大家族,一个是Collection家族,Collection家族有三大成员:List、Queue、Set,这三大成员有三个子类(实际还有很多,这里不一一列举)分别是,ArrayList,LinkedList,HashSet,这个家族有一个特点,那就是他们都是单身,集合中的元素都是独立存在的。 另一个就是Map家族了,这个家族的特点就是他们都是成双成对(key和value)一起出现的,让Collection家族很是羡慕啊^_^。 如何使用常见的集合 创建LinkedList集合,并添加数据 LinkedList list = new LinkedList(); list.add("hello"); 创建HashSet集合,并添加数据 HashSet set = new HashSet(); set.add("hello"); 创建HashMap集合,并添加数据 HashMap map = new HashMap(); map.put("name","张三"); 以上就是创建几个常用集合创建实例并添加数据的方式,可以看到我们使用的方式除了LinkedList之外都是父类的引用指向子类对象,相信你还不陌生,这个我们在学习多态这个知识点的候讲过,这种方式可以大大的提高程序的可扩展性。 通过上述代码可以发现Map集合添加数据和Collection家族成员添加数据的方式不一样,Map集合添加数据必须有两个,即一个是Key一个是Value。 面试官 Duang Duang Duang面试官来啦,快坐好,摆好姿势。 好了,我要开始提问了: 问:Set集合List集合有什么区别呢? 答:Set集合中的数据不可重复,数据是无序的,List集合的数据可以重复,数据是有序的。 问:就没啦?[严肃脸] 答:哦哦,还有,Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变,List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变。 问:Map集合中的元素可以重复吗? 答:不可以! 问:你说一说,LinkedList和ArrayList的区别吧。 答:好嘞,LinkedList集合增删速度更快,ArrayList改查更快。 问:咳咳咳,下一位! 答:诶诶诶,别呀,我还没说完呢: ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。LinkedList是双向链表。 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。 面试官:嗯,这次算你过关,等下次通知吧! 我:...... 编程要求 请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下: 分别定义HashSet、ArrayList、LinkedList、HashMap集合。并向每一个集合中添加www.educoder.net,Map集合的key设置为address,最后将每一个集合返回。 测试说明 补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致,即为通过。 测试输入:无 预期输出: www.educoder.net www.educoder.net www.educoder.net www.educoder.net package step3; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; public class HelloWorld { public HashSet getHashSet(){ /********** Begin **********/ /********** End **********/ } public ArrayList getArrayList(){ /********** Begin **********/ /********** End **********/ } public LinkedList getLinkedList(){ /********** Begin **********/ /********** End **********/ } public Map getHashMap(){ /********** Begin **********/ /********** End **********/ } }
最新发布
03-18
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值