真正的大师,永远怀着一颗学徒的心
最近和同事聊天,说他手下的一个开发,工作 3 年多了,一个需求的技术点,需要循环删除 List 中的元素,整了半天,说程序报错,不会弄。。
他挺无语的,和我倾诉,我说工作 3 年多也不至于吧,不会的话,在网上找找也能搞定啊,他说确实是的,这个开发挺难带的,简直崩溃!!
循环删除 List 中的元素,这个问题是有需要的注意点的,如果是个新手,确实会遇到一点麻烦,但工作 3 年多,我觉得应该不至于啊,好吧,这篇文章就来梳理一下这其中的道道。
注:不管在什么业务场景下,都不要都不要对List使用for循环的同时,删除List集合中的元素
在阿里巴巴开发手册也明确说明禁止使用foreach删除、增加List元素。
下面举个实例场景,看一下为什么不能使用for循环
比如有如下的一个list:
public List
在上面的initList集合中,元素类型为String,有5个元素,怎么删除这些元素中包含字符''a''的元素。
@Test
public void remove1() {
List list = new ArrayList(initList);
for (int i = 0; i < list.size(); i++) {
if (list.get(i).contains("a")) {
list.remove(i);
}
}
System.out.println(list);
}
输出结果:[ab, abcd, bcd]
分析:
问题就出在 list.size(),因为 list.size() 和 i 都是动态变化的,索引为i的元素删除后,后边元素的索引自动向前补位,i 的值一直在累加,list.size() 一直在减少,所以 list 就会早早结束了循环。这种方式会导致只要每删除一个元素,就会漏掉下一个元素。
@Test
public void remove1() {
List list = new ArrayList(initList);
for (String str : list) {
if (str.contains("a")) {
list.remove(str);
}
}
System.out.println(list);
}
运行报错:
分析:
会导致Concurrent Modification Exception:并发修改异常
其实,for(xx in xx) 就是增强的 for循环,即迭代器 Iterator 的加强实现,其内部是调用的 Iterator 的方法,为什么会报ConcurrentModificationException 错误,我们来看下源码:
取下个元素的时候都会去判断要修改的数量(modCount)和期待修改的数量(expectedModCount)是否一致,不一致则会报错,而 ArrayList 中的 remove 方法并没有同步期待修改的数量(expectedModCount)值,所以会抛异常了。
把普通for循环例子的 size 提出变量,经行循环
@Test
public void remove2() {
List list = new ArrayList(initList);
int size = list.size();
for (int i = 0; i < size; i++) {
String str = list.get(i);
if (str.startsWith("a")) {
list.remove(i);
}
}
System.out.println(list);
}
运行报错:
分析:
这里问题显而易见,因为 size 变量是固定的,但 list 的实际大小是不断减小的,而 i 的大小是不断累加的,一旦 i >= list 的实际大小肯定就异常了。
@Test
public void remove4() {
List list = new ArrayList(initList);
for (Iterator iterator = list.iterator(); iterator.hasNext(); ) {
String str = iterator.next();
if (str.contains("a")) {
iterator.remove();
}
}
System.out.println(list);
}
输出结果:[bcd]
结果输出正常,所以,这种删除方法是安全的,推荐使用。
@Test
public void remove2() {
List list = new ArrayList(initList);
List list1 = list.stream()
.filter(f->!f.contains("a"))
.collect(Collectors.toList());
System.out.println(list1);
}
输出结果:[bcd]
结果输出正常,所以,这种删除方法是安全的,推荐使用,也是JAVA8的新特性。
使用迭代器循环迭代器
使用java8新特性Strem流的方式
页面更新:2024-03-21
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号