java中集合删除元素的两种常用方式及新手易错

本文介绍了Java中使用for循环和迭代器删除集合元素的两种方法,并强调了索引回溯的重要性及如何避免并发修改异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java中集合删除元素的两种常用方式及新手易错:

创建集合:

[java]  view plain  copy
  1. ArrayList<String> aList = new  ArrayList<String>();  
  2.         aList.add("a");  
  3.         aList.add("b");  
  4.         aList.add("c");  
  5.         aList.add("abc");  
  6.         aList.add("abc");  
  7.         aList.add("abc");  
  8.         aList.add("eye");  
  9.         aList.add("opp");  
  10.         aList.add("abc");  

1、第一种删除方式(利用for循环删除):

[java]  view plain  copy
  1. for (int i = 0; i < aList.size(); i++) {  
  2. if ("abc".equals(aList.get(i))) {  
  3. aList.remove(i--);// 索引回溯  
  4. }  
  5. }  

//和上面一样,换一种方式(易观看)

for (int i = 0; i < aList.size(); i++) {  
   if ("abc".equals(aList.get(i))) {  
       aList.remove(i);
        i--;// 索引回溯  
    }  
}





2、第二种删除方法(利用迭代器的remove()方法删除

[java]  view plain  copy
  1. ListIterator<String> listIterator = aList.listIterator();  
  2.         while(listIterator.hasNext()){  
  3.             String  str = listIterator.next();  
  4.             if ("abc".equals(str)) {  
  5.               //aList.remove(str);   // 集合自身的remove()方法删除  
  6.                 listIterator.remove(); //迭代器的remove() 方法删除  
  7.             }  
  8.         }  

运行结果:

[java]  view plain  copy
  1. 原集合:a b c abc abc abc eye opp abc   
  2. 删除后集合:a b c eye opp   


新手易错点:

1、利用for循环删除时索引没有回溯,导致漏删元素

[java]  view plain  copy
  1. for(int i = 0 ;i < aList.size(); i++){  
  2.             if("abc".equals(aList.get(i))){  
  3.                 aList.remove(i);// 索引回溯  
  4.             }  
  5.         }  


运行结果:

[java]  view plain  copy
  1. 原集合:a b c abc abc abc eye opp abc   
  2. 删除后集合:a b c abc eye opp   

2、使用迭代器循环删除元素时,没有利用迭代器remove方法删除元素而是利用集合自身的remove方法删除元素,

这样会导致“并发修改异常错误”

[java]  view plain  copy
  1. ListIterator<String> listIterator = aList.listIterator();  
  2.         while(listIterator.hasNext()){  
  3.             String  str = listIterator.next();  
  4.             if ("abc".equals(str)) {  
  5.                 aList.remove(str);   // 集合自身的remove()方法删除  
  6.             }  
  7.         }  
运行结果:

[java]  view plain  copy
  1. 原集合:a b c abc abc abc eye opp abc   
  2. 删除后集合:Exception in thread "main" java.util.ConcurrentModificationException  
  3.     at java.util.ArrayList$Itr.checkForComodification(Unknown Source)  
  4.     at java.util.ArrayList$Itr.next(Unknown Source)  
  5.     at practice_2.Mianpractice2.main(Mianpractice2.java:42)  


并发修改异常错误的产生是因为在生成迭代器后迭代器就已经确定了集合的长度size了,而后集合删除元素后集合的size变小,但是迭代器任然记录的是之前的size数据在迭代过程中产生并发修改异常ConcurrentModificationException,但是如果是使用迭代器的remove()方法来删除元素的话则不会产出这个问题,因为迭代器中的cursor能够自动适应元素删除后集合大小的变化;

所以在删除集合元素时,如果适应迭代器来循环集合元素一定要使用迭代器自身的remove()方法来删除元素;


转载出处:https://blog.youkuaiyun.com/u014143369/article/details/52996154


### Java集合中的常见错误及注意事项 #### 1. 并发修改异常 (`ConcurrentModificationException`) 当尝试在一个循环中直接修改集合的内容时,可能会引发 `ConcurrentModificationException`。这是因为某些集合实现(如 `ArrayList` 或 `HashSet`)不允许在其结构被修改的同时进行迭代操作。 例如,在以下代码片段中,试图通过增强型 `for` 循环删除元素会导致异常[^1]: ```java List<String> list = new ArrayList<>(); list.add("Item 1"); list.add("Item 2"); for (String item : list) { if (item.equals("Item 2")) { list.remove(item); // 抛出 ConcurrentModificationException } } ``` 为了避免此问题,可以改用 **Iterator** 的方式来安全地移除元素[^5]: ```java Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if ("Item 2".equals(item)) { iterator.remove(); // 安全移除 } } ``` --- #### 2. 同步控制缺失 如果多个线程同时访问并修改共享的可变集合,则可能导致数据不一致或其他并发问题。此时应考虑使用同步机制或线程安全的集合类。 例如,可以通过 `Collections.synchronizedList()` 方法将普通的列表转换为线程安全版本: ```java List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>()); ``` 对于更复杂的场景,推荐使用 `CopyOnWriteArrayList` 或其他专门设计用于多线程环境下的集合类型。 --- #### 3. 使用不当的集合类型 不同的集合具有各自的特性与适用范围。选择不适合当前需求的集合可能会影响性能甚至引入逻辑错误。以下是几个典型例子: - 如果需要频繁随机访问元素,优先选用基于索引的数据结构(如 `ArrayList`)。而链表形式的容器(如 `LinkedList`)更适合于大量插入/删除操作。 - 当存储唯一键值对映射关系时,应该采用哈希表族成员之一(如 `HashMap`, `TreeMap` 等),而不是简单数组或者普通列表[^2]。 --- #### 4. 整数包装类比较陷阱 在处理基本类型的封装对象时需要注意其内部缓存机制的影响。两个不同实例即使数值相等也可能因为内存地址差异而导致条件判断失败。因此建议始终利用 `.equals()` 方法代替原始运算符来进行深层对比测试[^3]。 示例说明如下所示: ```java Integer x = 3; Integer y = 3; System.out.println(x == y); // 输出 true, 因为自动拆箱后的 int 值相同且位于 JVM 缓存区间 [-128 至 127] Integer a = new Integer(3); Integer b = new Integer(3); System.out.println(a == b); // 输出 false, 尽管实际内容一样但由于它们属于独立实体所以引用并不匹配 System.out.println(a.equals(b)); // 正确做法,输出 true ``` --- #### 5. 集合到 Map 转换过程中的潜在风险 从一组记录构建关联字典时常需额外关注字段合法性验证以及重复项冲突解决策略等问题。假设存在两条完全相同的条目则最终结果只保留其中之一;另外还需警惕空指针隐患等情况发生。 一种简单的解决方案演示如下: ```java import java.util.*; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Person> people = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25) ); Map<String, Integer> map = people.stream() .collect(Collectors.toMap(Person::getName, Person::getAge)); System.out.println(map); } } class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } ``` 上述代码展示了如何借助流 API 实现高效便捷的地图初始化流程。 --- #### 总结 以上列举了几种常见的 Java 集合误用情形及其对应的预防措施。合理运用这些技巧有助于提升应用程序健壮性和运行效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值