List删除元素(fail-fast与fail-safe)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zx6571269/article/details/79967336

Iterator 接口 也是Java集合框架成员,它主要用来遍历(即迭代访问)Collection集合中的元素,Iterator 对象也称为迭代器

  • boolean hasNext(): 如果迭代中的集合元素没有被遍历完,则返回true

  • Object next(): 返回集合中的下一个元素

  • void remove(): 删除集合里上一次next方法返回的元素

Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。

for进行删除

  1. 可以正常删除元素
  2. 由于执行list.remove(i),list的长度减少了1,若是直接返回list.get(i)返回的是list.get(i+1)的值
  3. 如果想正常的获取删除的值可以先定义String str =null,再用str = list.get(i),最后在执行remove方法就可以获取删除元素的值了

list里面有a,b,c,d,e 元素

@Test
    public void testForRemove() {
        forRemove(list, "b");
        for(String str:list) {
            System.out.print(str+"\t");
        }

    }
    /*
     * 1. list.remove()成功时,list的长度变小一位
     *
     * 2.这里获取删除元素的值,list.get(i)获取删除的值,变为了list.get(i+1)的值
     */
    public static void forRemove(List<String> list,String target){
        for(int i = 0;i<list.size();i++){
            if(list.get(i).equals(target)){
                list.remove(i);
                //本来应该输出b,但是却输出c
                System.out.print(list.get(i)+"\t");

            }

        }

    }

image_1cm7if28g1gbi16s01ho9mn1gk51p.png-6.2kB
forRemove 这种方法,数据量大时,效率特别低

Iterator删除


    public static void IteratorRemove(List<String> list,String target){
        Iterator<String> iterator = list.iterator();

        while(iterator.hasNext()){
            String s  =  iterator.next();
            if(s.equals(target)){
                iterator.remove();
            }
        }
    }

Itreator 必须依附于Collection 对象,Iterator 迭代器采用的是快速失败(fail-fast)机制,一旦迭代过程中检测到该集合已经被修改(通常是程序中的其他线程修改),程序立即引发ConcurrentModificationException异常,而不是显示修改后的结果,这样可以避免共享资源引发的潜在问题
注意:

foreach(加强for循环)进行删除会出问题

循环迭代访问元素集合更加便捷,但是foreach循环中迭代变量也不是集合本身,当进行删除操作时,直接使用list.remove(),并不能在用于删除集合。对于加强for循环,经过编译后采用的是迭代器模式,来遍历,当进行删除,修改时会引发fail-fast(快速失败)

 public static void main(String[] args) {

        List<String> list = new ArrayList<>();

        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        for (String str : list) {
            if(str.equals("aaa")) {
                list.remove("aaa");
            }
        }

    }
}

反编译后可以看到,foreach使用的

public static void main(String[] args) {
        List<String> list = new ArrayList();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        Iterator var3 = list.iterator();

        while (var3.hasNext()) {
            String str = (String) var3.next();
            if (str.equals("aaa")) {
                list.remove("aaa"); //直接使用list.remove
            }
        }

    }

安全失败(fail—safe)

    采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。

    原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发ConcurrentModificationException。

    缺点:基于拷贝内容的优点是避免了ConcurrentModificationException,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

    场景:java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

参考1: Hollis直面java第45期
参考2: Java疯狂讲义

阅读更多

没有更多推荐了,返回首页