java List remove 时的小问题

本文讨论了在Java中使用ArrayList进行并发删除元素时出现的并发修改异常,并提供了两种有效的解决方法:逆序遍历和每删除一个元素后回退指针。通过实例演示了解决方案的应用。

 

From:http://hi.baidu.com/xiami9910/blog/item/caeda23621e560d8a2cc2b51.html

 

import java.util.*;

public class object {

public static void main(String[] args) {

   String str1 = new String("abcde");

   String str2 = new String("abcde");

   String str3 = new String("abcde");

   String str4 = new String("abcde");

   String str5 = new String("abcde");

   List list = new ArrayList();

   list.add(str1);

   list.add(str2);

   list.add(str3);

   list.add(str4);

   list.add(str5);

   System.out.println("list.size()=" + list.size());

   for (int i = 0; i < list.size(); i++) {

    if (((String) list.get(i)).startsWith("abcde")) {

     list.remove(i);

    }

   }

   System.out.println("after remove:list.size()=" + list.size());

}

}

 

运行结果不是:

 

list.size()=5

after remove:list.size()=0

 

居然是:

 

list.size()=5

after remove:list.size()=2

 

原因:List每remove掉一个元素以后,后面的元素都会向前移动,此时如果执行i=i+1,则刚刚移过来的元素没有被读取。

 

解决方法:

 

1.倒过来遍历list

 

for (int i = list.size()-1; i > =0; i--) {

    if (((String) list.get(i)).startsWith("abcde")) {

     list.remove(i);

    }

}

 

2.每移除一个元素以后再把i移回来

 

for (int i = 0; i < list.size(); i++) {

    if (((String) list.get(i)).startsWith("abcde")) {

     list.remove(i);

     i=i-1;

 

   }

}

 

======================================================================

边遍历ArrayList边删除元素抛java.util.ConcurrentModification 

执行下列代码:

 

if (CollectionUtils.isNotEmpty(list)) {

  Iterator it = list.iterator();

  while (it.hasNext()) {

 OfferMigPlan offerMigPlan = (OfferMigPlan) it.next();

 if(setCommonAttributes(offerMigPlan)==null){

 list.remove(offerMigPlan);

  }

 }

}

 

 

抛出异常java.util.ConcurrentModification,为什么?因为我们在遍历的时候,删除了list里面的一个元素,相应的后面的元素都在list中网上进一个位置,然而在迭代器的相应位置却未删除。

 

Solution:使用Iterator.remove()方法,该方法可删除由Iterator生成的上一个元素。所以每次调用next()的时候,只需调用remove()一次。

 

if (CollectionUtils.isNotEmpty(list)) {

  Iterator it = list.iterator();

  while (it.hasNext()) {

 OfferMigPlan offerMigPlan = (OfferMigPlan) it.next();

 if(setCommonAttributes(offerMigPlan)==null){

 

  it.remove();

 list.remove(offerMigPlan);

  }

 }

}

 

<think> 我们正在讨论JavaListremoveIf方法。用户已经提供了一些引用,但我们需要主要关注removeIf方法本身。 引用[1]提到了removeIf是Collection接口的默认方法(Java8新增),底层实现是通过迭代迭代每一个元素,满足条件的通过remove()方法删除。 引用[2]提到了remove方法的一个坑:当List中存放的是Integer对象,调用remove(int index)和remove(Object object)的重载问题,但removeIf方法没有这个问题,因为removeIf的参数是Predicate。 因此,我们将围绕removeIf方法进行讲解: 1. 使用方式:介绍removeIf的基本用法,包括参数和返回值。 2. 原理:根据引用[1]的说明,解释其内部实现机制。 3. 注意事项:包括并发修改异常、性能考虑、以及和迭代remove的对比等。 注意:用户可能对removeIf和remove之间的区别和联系感兴趣,所以可以适当提及。 另外,用户提供的引用[2]主要讲的是remove方法的坑,我们可以指出removeIf方法避免了这种重载问题,因为它是根据条件来删除,而不是根据索引或对象。 结构如下: 一、方法定义 二、使用示例 三、实现原理 四、注意事项 五、与remove方法的对比 最后,生成相关问题。 </think>### Java List `removeIf()` 方法详解 `removeIf()` 是 Java 8 引入的 `Collection` 接口默认方法,专为安全高效地批量删除集合元素而设计。 #### 一、方法定义与语法 ```java default boolean removeIf(Predicate<? super E> filter) ``` - **参数**:`Predicate` 函数式接口(接收元素,返回 `boolean`) - **返回值**:`true`(至少删除一个元素)或 `false`(无元素被删除) - **示例**: ```java List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); boolean changed = numbers.removeIf(n -> n % 2 == 0); // 删除所有偶数 // 结果:numbers = [1, 3, 5], changed = true ``` #### 二、底层实现原理 依据引用[^1]描述: 1. 获取集合的迭代器 `Iterator` 2. 遍历每个元素,用 `Predicate` 测试条件 3. 对满足条件的元素调用迭代器的 `remove()` 4. 返回 `true`(有删除)或 `false`(无删除) > **关键特性**:内部使用迭代器删除,避免了 `ConcurrentModificationException`[^1] #### 三、使用场景与示例 1. **基础过滤**(删除空值): ```java List<String> words = new ArrayList<>(List.of("a", null, "b")); words.removeIf(Objects::isNull); // 结果: ["a", "b"] ``` 2. **复合条件删除**: ```java users.removeIf(user -> user.getAge() < 18 || "admin".equals(user.getRole()) ); ``` 3. **与流式操作对比**: ```java // 等效流操作(需重新赋值) words = words.stream() .filter(Objects::nonNull) .collect(Collectors.toList()); ``` #### 四、注意事项 1. **避免引用[^2]中的陷阱** `removeIf` 无需区分 `remove(int)` 和 `remove(Object)`,规避了整数列表的删除歧义: ```java List<Integer> nums = new ArrayList<>(List.of(100, 200, 300)); nums.removeIf(n -> n == 100); // 正确删除元素100(而非索引100) ``` 2. **并发安全** - 非线程安全集合需加锁: ```java synchronized (list) { list.removeIf(...); } ``` - 建议使用 `CopyOnWriteArrayList` 替代 3. **性能优化** - 对 `LinkedList` 建议改用迭代器手动删除 - 超大集合分批处理: ```java while (list.removeIf(condition)) { // 分批执行避免长间阻塞 } ``` #### 五、与 `remove()` 方法对比 | 特性 | `removeIf()` | `remove()` | |---------------------|---------------------------------------|--------------------------------| | 删除方式 | 批量条件删除 | 单元素删除(索引或对象) | | 重载歧义 | 无(参数固定为`Predicate`) | 需区分`remove(int)`/`remove(Object)`[^2] | | 异常风险 | 无`ConcurrentModificationException` | 遍历直接调用会抛异常 | | Java版本 | 8+ | 全版本 | > **最佳实践**:优先用 `removeIf` 代替循环 + 迭代器删除,代码更简洁安全。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值