java基础之:ArrayList删除问题以及解决方案?

本文探讨了在Java中使用ArrayList删除重复元素时遇到的问题,即调用remove方法无法完全删除所有重复值。原因在于ArrayList的remove方法在删除元素后导致后续元素前移,从而在遍历过程中遗漏部分元素。文章提供了两种解决方案:一是采用倒序遍历避免遗漏;二是通过先转换为Set去重,然后再删除目标元素。
摘要由CSDN通过智能技术生成

java基础之:ArrayList删除问题以及解决方案?

在一个ArrayList中需要remove的元素在集合中存在重复值

        List<String> list = new ArrayList<>();
        list.add("abc");
        list.add("abc");
        list.add("abc");
        list.add("abc");
        list.add("abc");
        for (int i = 0; i < list.size(); i++) {
            list.remove("abc"); //删除元素值为abc的元素
        }

控制台输出结果显示:

C:\Soft\Java\jdk1.8.0_211\bin\java.exe "-javaagent:D:\Program Files\JetBrains\apps\IDEA-U\ch-0\193.7288.26\lib\idea_rt.jar=57860:D:\Program Files\JetBrains\apps\IDEA-U\ch-0\193.7288.26\bin" -Dfile.encoding=UTF-8 -classpath C:\Soft\Java\jdk1.8.0_211\jre\lib\charsets.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\deploy.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\access-bridge-64.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\cldrdata.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\dnsns.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\jaccess.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\jfxrt.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\localedata.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\nashorn.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\sunec.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\sunjce_provider.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\sunmscapi.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\sunpkcs11.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\ext\zipfs.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\javaws.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\jce.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\jfr.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\jfxswt.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\jsse.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\management-agent.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\plugin.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\resources.jar;C:\Soft\Java\jdk1.8.0_211\jre\lib\rt.jar;D:\workspace\springboot\concurrency\target\classes;D:\localRepository\org\springframework\boot\spring-boot-starter-web\1.5.9.RELEASE\spring-boot-starter-web-1.5.9.RELEASE.jar;D:\localRepository\org\springframework\boot\spring-boot-starter\1.5.9.RELEASE\spring-boot-starter-1.5.9.RELEASE.jar;D:\localRepository\org\springframework\boot\spring-boot\1.5.9.RELEASE\spring-boot-1.5.9.RELEASE.jar;D:\localRepository\org\springframework\boot\spring-boot-autoconfigure\1.5.9.RELEASE\spring-boot-autoconfigure-1.5.9.RELEASE.jar;D:\localRepository\org\springframework\boot\spring-boot-starter-logging\1.5.9.RELEASE\spring-boot-starter-logging-1.5.9.RELEASE.jar;D:\localRepository\ch\qos\logback\logback-classic\1.1.11\logback-classic-1.1.11.jar;D:\localRepository\ch\qos\logback\logback-core\1.1.11\logback-core-1.1.11.jar;D:\localRepository\org\slf4j\jcl-over-slf4j\1.7.25\jcl-over-slf4j-1.7.25.jar;D:\localRepository\org\slf4j\jul-to-slf4j\1.7.25\jul-to-slf4j-1.7.25.jar;D:\localRepository\org\slf4j\log4j-over-slf4j\1.7.25\log4j-over-slf4j-1.7.25.jar;D:\localRepository\org\yaml\snakeyaml\1.17\snakeyaml-1.17.jar;D:\localRepository\org\springframework\boot\spring-boot-starter-tomcat\1.5.9.RELEASE\spring-boot-starter-tomcat-1.5.9.RELEASE.jar;D:\localRepository\org\apache\tomcat\embed\tomcat-embed-core\8.5.23\tomcat-embed-core-8.5.23.jar;D:\localRepository\org\apache\tomcat\tomcat-annotations-api\8.5.23\tomcat-annotations-api-8.5.23.jar;D:\localRepository\org\apache\tomcat\embed\tomcat-embed-el\8.5.23\tomcat-embed-el-8.5.23.jar;D:\localRepository\org\apache\tomcat\embed\tomcat-embed-websocket\8.5.23\tomcat-embed-websocket-8.5.23.jar;D:\localRepository\org\hibernate\hibernate-validator\5.3.6.Final\hibernate-validator-5.3.6.Final.jar;D:\localRepository\javax\validation\validation-api\1.1.0.Final\validation-api-1.1.0.Final.jar;D:\localRepository\org\jboss\logging\jboss-logging\3.3.1.Final\jboss-logging-3.3.1.Final.jar;D:\localRepository\com\fasterxml\classmate\1.3.4\classmate-1.3.4.jar;D:\localRepository\com\fasterxml\jackson\core\jackson-databind\2.8.10\jackson-databind-2.8.10.jar;D:\localRepository\com\fasterxml\jackson\core\jackson-annotations\2.8.0\jackson-annotations-2.8.0.jar;D:\localRepository\com\fasterxml\jackson\core\jackson-core\2.8.10\jackson-core-2.8.10.jar;D:\localRepository\org\springframework\spring-web\4.3.13.RELEASE\spring-web-4.3.13.RELEASE.jar;D:\localRepository\org\springframework\spring-aop\4.3.13.RELEASE\spring-aop-4.3.13.RELEASE.jar;D:\localRepository\org\springframework\spring-beans\4.3.13.RELEASE\spring-beans-4.3.13.RELEASE.jar;D:\localRepository\org\springframework\spring-context\4.3.13.RELEASE\spring-context-4.3.13.RELEASE.jar;D:\localRepository\org\springframework\spring-webmvc\4.3.13.RELEASE\spring-webmvc-4.3.13.RELEASE.jar;D:\localRepository\org\springframework\spring-expression\4.3.13.RELEASE\spring-expression-4.3.13.RELEASE.jar;D:\localRepository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;D:\localRepository\org\springframework\spring-core\4.3.13.RELEASE\spring-core-4.3.13.RELEASE.jar;D:\localRepository\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar;D:\localRepository\com\google\guava\guava\23.0\guava-23.0.jar;D:\localRepository\com\google\code\findbugs\jsr305\1.3.9\jsr305-1.3.9.jar;D:\localRepository\com\google\errorprone\error_prone_annotations\2.0.18\error_prone_annotations-2.0.18.jar;D:\localRepository\com\google\j2objc\j2objc-annotations\1.1\j2objc-annotations-1.1.jar;D:\localRepository\org\codehaus\mojo\animal-sniffer-annotations\1.14\animal-sniffer-annotations-1.14.jar;D:\localRepository\joda-time\joda-time\2.9\joda-time-2.9.jar;D:\localRepository\redis\clients\jedis\2.8.2\jedis-2.8.2.jar;D:\localRepository\org\apache\commons\commons-pool2\2.4.3\commons-pool2-2.4.3.jar com.mmall.concurrency.example.testdemo.TestArrayListRemove
abc
abc

Process finished with exit code 0


问题:为什么调用remove删除list中的abc元素,abc元素不会全部删除呢?

因为查看源码可知,remove方法真正实现元素删除是调用了fastRemove方法

    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

fastRemove方法是怎么实现元素删除的呢?
因为ArrayList底层是数组实现的,所以当ArrayList删除了一个元素,则将此元素后的所有元素往前移一位,并将集合长度-1。因为元素移动,所以在遍历到第一个"abc"(下标为0)并删除掉后,第二个紧随的"abc"会移动到下标为0的位置。但下次遍历时,会从下标1处开始继续遍历,所以此时移动到0的元素不会被遍历到了,依次类推,所以最后会有两个"abc"被遗漏下来。

    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }

解决方案一:采用倒序遍历方式来避免遗漏的情况发生

   for (int i = list.size(); i >0; i--) {
            list.remove("abc");
        }

解决方案二:先TreeSet/HashSet去除重复元素,然后利用List和Set之间转换关系

        List<String> list = new ArrayList<>();
        list.add("abc");
        list.add("abc");
        list.add("abc");
        list.add("abc");
        list.add("abc");
        Set<String> set = new TreeSet<>(list);
        List<String> list2 = new ArrayList<>(set);
        for (int i = 0; i < list2.size(); i++) {
            list2.remove("abc");
        }
        for (String s : list2) {
            System.out.println(s);
        }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值