集合边遍历(for循环)边删除为什么删不干净 及三种实现删除的方法

  • Post author:
  • Post category:其他


为什么说数组边for循环遍历边删除会出现删不干净的情况



1、为什么删不干净

先写一个例子:可以先猜一下控制台会打印出什么内容?

public class removeIterator {

    public static void main(String[] args) {
    //ArrayList的底层数据结构就是数组
        List<String>list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        for(int i=0;i<list.size();i++){
            list.remove(i);
        }
        System.out.println(list.toString());
    }
}

公布答案:

在这里插入图片描述

可以看到,并没有全部移除掉(猜对没?)。那这是为什么呢?

一开始,list中是这样的:

在这里插入图片描述

当移除下标为0的元素后,index+1=1,而元素bbb及之后的元素都向前移动了一位,如下图:

在这里插入图片描述

接下来要移除index==1位置上的元素,也就是移除ccc,移除ccc后,ddd的下标变为1,而index+1=2,即不会移除ddd,所以最后list剩下了bbb和ddd:

在这里插入图片描述


那么如何才可以稳定的删除呢,总结了以下三种方法:



倒序删

倒序删不会出现上面例子中元素数组位置改变的情况。

public class removeIterator {

    public static void main(String[] args) {
        List<String>list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        for(int i=list.size()-1;i>=0;i--){
            list.remove(i);
        }
        System.out.println(list.toString());
    }
}

结果:

在这里插入图片描述

移除指定元素:

 public static void descRemove(List<Integer>list,Integer val){
        for(int i=list.size()-1;i>=0;i--){
            if(list.get(i)==val){
                list.remove(i);
            }
        }
    }



迭代器

使用 Iterator.remove() 方法

简单介绍一下这个方法:

  1. Collection接口实现了Iterable接口,实现了Iterable接口的类可以拥有增强for循环
  2. Iterator的remove()方法优势

    如果知道删除项的准确位置,删除操作的开销小

    不能对正在被遍历的集合进行改变(add,remove,clear等操作),但是可以调用iterator中的remove方法进行删除
public class removeIterator {

    public static void main(String[] args) {
        List<String>list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            it.next();
            it.remove();
        }
        System.out.println(list.toString());
    }
}

-----结果-----
[]

注:如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,再调用remove都会报IllegalStateException。

删除指定元素:

List<Integer>list=new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(6);
        list.add(3);
        System.out.println(list.size());
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            if( iterator.next().equals(3)){
                iterator.remove();
            }
        }
        System.out.println(list.toString()+":size="+list.size());

在这里插入图片描述



lambda表达式删除

上面使用迭代器的方式虽然能够正常的删除列表中的元素,但是不够优雅,因为要写好几行的遍历代码,显得略臃肿。能不能只用一行代码完成这个功能呢?答案是可以的——使用Lambda表达式:


删除指定条件的元素:

  public String getString(List<Integer> list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        list.removeIf(e -> isNotValid(e));
        return list.stream().map(String::valueOf).collect(Collectors.joining(","));
    }

    private static Boolean isNotValid(Integer in) {
        if (in == null) {//为空的为无效数字
            return true;
        }
        return false;
    }
//输入:[1,2,3,null,5,null,7]
//输出:"1,2,3,5,7"

示例2

 public static void lambdaRemove(List<Integer>list,Integer val){
        list.removeIf(e->e==val);
    }



版权声明:本文为m0_51963973原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。