做了3年的开发,不会循环删除List中的元素,心态崩了
真正的大师,永远怀着一颗学徒的心
最近和同事聊天,说他手下的一个开发,工作3年多了,一个需求的技术点,需要循环删除List中的元素,整了半天,说程序报错,不会弄
他挺无语的,和我倾诉,我说工作3年多也不至于吧,不会的话,在网上找找也能搞定啊,他说确实是的,这个开发挺难带的,简直崩溃!!
循环删除List中的元素,这个问题是有需要的注意点的,如果是个新手,确实会遇到一点麻烦,但工作3年多,我觉得应该不至于啊,好吧,这篇文章就来梳理一下这其中的道道。1。List中删除元素1。1前言
注:不管在什么业务场景下,都不要都不要对List使用for循环的同时,删除List集合中的元素
在阿里巴巴开发手册也明确说明禁止使用foreach删除、增加List元素。1。2问题
下面举个实例场景,看一下为什么不能使用for循环
比如有如下的一个list:
publicListinitListArrays。asList(a,ab,abc,abcd,bcd);1。3需求
在上面的initList集合中,元素类型为String,有5个元素,怎么删除这些元素中包含字符a的元素。1。4方法1。4。1普通for循环删除(不可靠)Testpublicvoidremove1(){ListStringlistnewArrayList(initList);for(inti0;ilist。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就会早早结束了循环。这种方式会导致只要每删除一个元素,就会漏掉下一个元素。1。4。2增强for循环删除(不可靠)Testpublicvoidremove1(){ListStringlistnewArrayList(initList);for(Stringstr:list){if(str。contains(a)){list。remove(str);}}System。out。println(list);}
运行报错:
分析:
会导致ConcurrentModificationException:并发修改异常
其实,for(xxinxx)就是增强的for循环,即迭代器Iterator的加强实现,其内部是调用的Iterator的方法,为什么会报ConcurrentModificationException错误,我们来看下源码:
取下个元素的时候都会去判断要修改的数量(modCount)和期待修改的数量(expectedModCount)是否一致,不一致则会报错,而ArrayList中的remove方法并没有同步期待修改的数量(expectedModCount)值,所以会抛异常了。1。4。3普通for循环提取变量删除(抛异常)
把普通for循环例子的size提出变量,经行循环Testpublicvoidremove2(){ListStringlistnewArrayList(initList);intsizelist。size();for(inti0;isize;i){Stringstrlist。get(i);if(str。startsWith(a)){list。remove(i);}}System。out。println(list);}
运行报错:
分析:
这里问题显而易见,因为size变量是固定的,但list的实际大小是不断减小的,而i的大小是不断累加的,一旦ilist的实际大小肯定就异常了。1。4。4迭代器循环迭代器删除(可靠)Testpublicvoidremove4(){ListStringlistnewArrayList(initList);for(IteratorStringiteratorlist。iterator();iterator。hasNext();){Stringstriterator。next();if(str。contains(a)){iterator。remove();}}System。out。println(list);}
输出结果:〔bcd〕
结果输出正常,所以,这种删除方法是安全的,推荐使用。1。4。5新特性stream进行List去重(可靠)Testpublicvoidremove2(){ListStringlistnewArrayList(initList);ListStringlist1list。stream()。filter(f!f。contains(a))。collect(Collectors。toList());System。out。println(list1);}
输出结果:〔bcd〕
结果输出正常,所以,这种删除方法是安全的,推荐使用,也是JAVA8的新特性。1。5结论
使用迭代器循环迭代器
使用java8新特性Strem流的方式