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

  本篇文章为你整理了带了一个 3 年的开发,不会循环删除 List 中的元素,心态崩了。。(foreach循环删除list元素)的详细内容,包含有list循环remove删除自身list中的值 foreach循环删除list元素 list for循环为什么不能删除 list foreach删除 带了一个 3 年的开发,不会循环删除 List 中的元素,心态崩了。。,希望能帮助你了解 带了一个 3 年的开发,不会循环删除 List 中的元素,心态崩了。。。

  分享Java技术,高并发编程,分布式技术,架构设计,Java面试题,算法,行业动态,程序人生等。

  
大家好,我是栈长。

  最近和某个朋友聊天,说他手下的一个开发,工作 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 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开发手册(嵩山版)》最新发布,速速下载!

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

  以上就是带了一个 3 年的开发,不会循环删除 List 中的元素,心态崩了。。(foreach循环删除list元素)的详细内容,想要了解更多 带了一个 3 年的开发,不会循环删除 List 中的元素,心态崩了。。的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: