首页IT科技list iterator删除(带了一个 3 年的开发,不会循环删除 List 中的元素,心态崩了。。)

list iterator删除(带了一个 3 年的开发,不会循环删除 List 中的元素,心态崩了。。)

时间2025-05-01 09:25:51分类IT科技浏览3677
导读:大家好,我是栈长。...

大家好            ,我是栈长            。

最近和某个朋友聊天                 ,说他手下的一个开发     ,工作 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(); ite.hasNext(); ) { String str = ite.next(); if (str.contains("李")) { list.remove(str); } } System.out.println(list); }

输出结果:

又是那个并发修改异常                  ,这个示例虽然使用了 Iterator 循环           ,但删除的时候却使用了 list.remove 方法      ,同样是有问题的                  ,注意了           ,千万别用错了                 。

7      、集合 forEach 方法循环删除(抛异常) /** * list.forEach 删除 * @author: 栈长 * @from: 公众号Java技术栈 */ @Test public void remove6() { List<String> list = new ArrayList(initList); list.forEach((e) -> { if (e.contains("李")) { list.remove(e); } }); System.out.println(list); }

输出结果:

forEach 源码:

forEach 方法的背后其实就是增强的 for 循环,底层即迭代器                  ,所以使用 list.remove 同样抛出 ConcurrentModificationException 异常。

8                 、stream filter 过滤(可靠) /** * stream filter 过滤 * @author: 栈长 * @from: 公众号Java技术栈 */ @Test public void remove7() { List<String> list = new ArrayList(initList); list = list.stream().filter(e -> !e.startsWith("李")).collect(Collectors.toList()); System.out.println(list); }

输出结果:

[张三, 周一, 刘四]

Stream filter 的详细用法                 ,栈长之前已经分享过:你还在遍历搜索集合?别逗了!Java 8 一行代码搞定,是真的优雅!            ,没看过的点回去看看吧            。

这个方法即是利用了 Stream 的筛选功能                 ,快速过滤所需要的元素     ,虽然不是进行集合删除            ,但达到了同样的目的                  ,这种方法要更简洁吧                 。

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

https://github.com/javastacks/javastack

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

总结

本文总结了 8 种循环删除 List 元素的方法:

普通 for 循环删除(不可靠) 普通 for 循环提取变量删除(抛异常) 普通 for 循环倒序删除(可靠) 增强 for 循环删除(抛异常) 迭代器循环迭代器删除(可靠) 迭代器循环集合删除(抛异常) 集合 forEach 方法循环删除(抛异常) stream filter 过滤(可靠)

可靠            、可行的方案也只有 3 种      ,正统的删除法也就 2 种                  ,但也要注意别用错了方法           ,所以也理解那个小伙子说怎么搞都搞不定      ,估计也是走了不少弯路                  ,或者没有找对方法吧     。

你还知道哪些删除技巧?欢迎留言分享~

好了           ,今天的分享就到这里了,后面栈长会分享更多好玩的 Java 技术和最新的技术资讯                  ,关注公众号Java技术栈第一时间推送                 ,我也将主流 Java 面试题和参考答案都整理好了,在公众号后台回复关键字 "面试" 进行刷题            。

最后            ,留个话题:

怎么去除 List<String> 中的重复元素呢?

下期分享                 ,等栈长写完     ,公众号Java技术栈第一时间推送            ,不要走开~

版权声明: 本文系公众号 "Java技术栈" 原创                  ,转载、引用本文内容请注明出处     ,抄袭                 、洗稿一律投诉侵权      ,后果自负                  ,并保留追究其法律责任的权利                  。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了     。      。                  。

3.Spring Boot 2.x 教程           ,太全了!

4.别再写满屏的爆爆爆炸类了      ,试试装饰器模式                  ,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布           ,速速下载!

觉得不错,别忘了随手点赞+转发哦!

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
网络适配器感叹号代码56(网络适配器感叹号解决方法) seo原创模板(seo智能伪原创)