设为首页 加入收藏

TOP

带了一个 3 年的开发,不会循环删除 List 中的元素,心态崩了。。(一)
2023-07-26 08:16:57 】 浏览:57
Tags:3年 List 元素

大家好,我是栈长。

最近和某个朋友聊天,说他手下的一个开发,工作 3 年多了,一个需求的技术点,需要循环删除 List 中的元素,整了半天,说程序报错,不会弄。。

他挺无语的,和我倾诉,我说工作 3 年多也不至于吧,不会的话,在网上找找也能搞定啊,他说确实是的,这个开发挺难带的,简直崩溃!!

循环删除 List 中的元素,这个问题是有需要的注意点的,如果是个新手,确实会遇到一点麻烦,但工作 3 年多,我觉得应该不至于啊,好吧,这篇栈长就来梳理一下这其中的道道。


问题

比如有以下这个 List:

public List<String> initList = Arrays.asList("张三", "李四", "周一", "刘四", "李强", "李白");

怎么删除 List 中姓李的人?


方法

我来们分析下有可行的方法!

本文所有完整示例源代码已经上传:

https://github.com/javastacks/javastack

欢迎 Star 学习,后面 Java 示例都会在这上面提供!

1、普通 for 循环删除(不可靠)

/**
 * 普通 for 循环删除
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove1() {
    List<String> list = new ArrayList(initList);
    for (int i = 0; i < list.size(); i++) {
        String str = list.get(i);
        if (str.startsWith("李")) {
            list.remove(i);
        }
    }
    System.out.println(list);
}

输出结果:

[张三, 周一, 刘四, 李白]

WC,李白没删干净?

问题就出在 list.size(),因为 list.size() 和 i 都是动态变化的,i 的值一直在累加,list.size() 一直在减少,所以 list 就会早早结束了循环。

所以这种方式虽然不会报错,但存在隐患,并且不容易被察觉,不建议使用。

2、普通 for 循环提取变量删除(抛异常)

把上面的示例中的 size 提出变量:

/**
 * 普通 for 循环删除(size提出变量)
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove2() {
    List<String> list = new ArrayList(initList);
    int size = list.size();
    for (int i = 0; i < size; i++) {
        String str = list.get(i);
        if (str.startsWith("李")) {
            list.remove(i);
        }
    }
    System.out.println(list);
}

输出结果:

好家伙,都直接干下标溢出异常了。。

这里也很明显,因为 size 变量是固定的,但 list 的实际大小是不断减小的,而 i 的大小是不断累加的,一旦 i >= list 的实际大小肯定就异常了。

3、普通 for 循环倒序删除(可靠)

/**
 * 普通 for 循环倒序删除
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove3() {
    List<String> list = new ArrayList(initList);
    for (int i = list.size() - 1; i > 0; i--) {
        String str = list.get(i);
        if (str.startsWith("李")) {
            list.remove(i);
        }
    }
    System.out.println(list);
}

输出结果:

[张三, 周一, 刘四]

结果输出正常,这种删除方式就算把 list.size() 提出变量也是 OK 的,因为循环中只用到了一次。

4、增强 for 循环删除(抛异常)

/**
 * 增强 for 循环删除
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove3() {
    List<String> list = new ArrayList(initList);
    for (String element : list) {
        if (element.startsWith("李")) {
            list.remove(element);
        }
    }
    System.out.println(list);
}

输出结果:

好家伙,又抛异常了。不过这次的异常和上面的下标异常不太一样,这次是:

java.util.ConcurrentModificationException

这个是集合操作中很常见的异常之一,即并发修改异常!

其实,for(xx in xx) 就是增强的 for循环,即迭代器 Iterator 的加强实现,其内部是调用的 Iterator 的方法,为什么会报 ConcurrentModificationException 错误,我们来看下源码:

取下个元素的时候都会去判断要修改的数量(modCount)和期待修改的数量(expectedModCount)是否一致,不一致则会报错,而 ArrayList 中的 remove 方法并没有同步期待修改的数量(expectedModCount)值,所以会抛异常了。

另外,最新最全的 Java 面试题整理好了,共 1800+,微信搜索Java面试库小程序在线刷题。

5、迭代器循环迭代器删除(可靠)

/**
 * 迭代器循环删除(iterator.remove)
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove4() {
    List<String> list = new ArrayList(initList);
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
        String str = iterator.next();
        if (str.contains("李")) {
            iterator.remove();
        }
    }
    System.out.println(list);
}

输出结果:

[张三, 周一, 刘四]

结果输出正常,这是因为迭代器中的 remove 方法将期待修改的数量(expectedModCount)值进行了同步:

所以,这种删除方法是安全的,推荐使用。

6、迭代器循环集合删除(抛异常)

/**
 * 迭代器循环删除(list.remove)
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove5() {
    List<String> list = new ArrayList(initList);
    for (Iterator<String> ite = list.iterator(
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇《分布式技术原理与算法解析》学.. 下一篇docker搭建maven私服(nexus3),..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目