在java中,List的删除操作可能会导致ConcurrentModificationException一场,尤其是在遍历时直接调用removce(方法)
一、使用Iterator删除
Iterator提供了安全的删除方法remove(),可以在遍历时删除元素
List<String> list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if (item.equals("B")) { iterator.remove(); // 安全删除 } } System.out.println(list); // 输出: [A, C]
优点:
-
安全且高效
-
适用于单线程环境
二、使用removeIf(方法)(java8+)
java8引入了removeIf方法,可以根据条件删除元素
List<String> list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); list.removeIf(item -> item.equals("B")); // 删除满足条件的元素 System.out.println(list); // 输出: [A, C]
优点:
-
代码简洁,适合函数式编程风格。
-
内部使用
Iterator
,安全高效。
三、使用for循环倒序遍历
如果使用普通的for循环删除元素,建议倒序遍历,避免索引错误问题
List<String> list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); for (int i = list.size() - 1; i >= 0; i--) { if (list.get(i).equals("B")) { list.remove(i); // 删除元素 } } System.out.println(list); // 输出: [A, C]
优点:
-
避免索引错位问题。
-
适用于需要根据索引删除的场景。
四、使用CopyOnWriteArrayList
如果需要在多线程环境下安全删除元素,可以使用CopyOnWriteArrayList,它在修改时创建底层数据的新副本,适合多读写啊后的场景
List<String> list = new CopyOnWriteArrayList<>(); list.add("A"); list.add("B"); list.add("C"); for (String item : list) { if (item.equals("B")) { list.remove(item); // 安全删除 } } System.out.println(list); // 输出: [A, C]
注意:
-
CopyOnWriteArrayList
的写操作性能较差,因为每次修改都会创建新副本。 -
适合多线程环境。
五、使用Collections.synchronizedList加锁
如果使用Collecions.synchronizedList包装List,需要手动加锁以保证线程安全
List<String> list = Collections.synchronizedList(new ArrayList<>()); list.add("A"); list.add("B"); list.add("C"); synchronized (list) { Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if (item.equals("B")) { iterator.remove(); // 安全删除 } } } System.out.println(list); // 输出: [A, C]
优点:
-
线程安全。
-
适用于多线程环境
六、使用Stream过滤
如果需要删除满足条件的元素并生成新表,可以使用Stream的filter方法
List<String> list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); List<String> result = list.stream() .filter(item -> !item.equals("B")) // 过滤掉 "B" .collect(Collectors.toList()); System.out.println(result); // 输出: [A, C]
优点:
-
不修改原列表,生成新列表。
-
适合函数式编程风格。
总结
方法 | 适用场景 | 特点 |
---|---|---|
Iterator.remove() | 单线程环境 | 安全高效 |
removeIf() | Java 8+,单线程环境 | 简洁,适合函数式编程 |
倒序遍历 for 循环 | 根据索引删除 | 避免索引错位 |
CopyOnWriteArrayList | 多线程环境 | 线程安全,适合读多写少 |
Collections.synchronizedList + 锁 | 多线程环境 | 线程安全,需要手动加锁 |
Stream.filter() | 生成新列表 | 不修改原列表,适合函数式编程 |