初始化一个List容器
问题:博主平时喜欢打王者荣耀这种moba类推塔游戏,喜欢玩的位置是上单,俗称孤儿对抗路。在List容器中放入吕布、马超等8个英雄,其中有2个不属于对抗路,请删除 List 中姓李的这两个打野英雄,你有几种方式呢?
1.普通 for 循环删除(不可靠)
输出结果:
WC,李信没删干净?
问题就出在 list.size(),因为 list.size() 和 i 都是动态变化的,i 的值一直在累加,list.size() 一直在减少,所以 list 就会早早结束了循环。
所以这种方式虽然不会报错,但存在隐患,并且不容易被察觉,不建议使用。
2.普通 for 循环提取变量删除(抛异常)
输出结果:
额,报数组下标越界异常
这里也很明显,因为 size 变量是固定的,但 list 的实际大小是不断减小的,而 i 的大小是不断累加的,一旦 i >= list 的实际大小肯定就异常了。
3.普通 for 循环倒序删除(可靠)
输出结果:
结果输出正常,这种删除方式就算把 list.size() 提出变量也是 OK 的,因为循环中只用到了一次。
4.增强 for 循环删除(抛异常)
输出结果:
又抛异常了。不过这次的异常和上面的下标异常不太一样,这次是:java.util.ConcurrentModificationException
这个是集合操作中很常见的异常之一,即并发修改异常。
其实,for(xx in xx) 就是增强的 for循环,即迭代器 Iterator 的加强实现,其内部是调用的 Iterator 的方法,为什么会报 ConcurrentModificationException 错误,我们来看下源码:
取下个元素的时候都会去判断要修改的数量(modCount)和期待修改的数量(expectedModCount)是否一致,不一致则会报错,而 ArrayList 中的 remove 方法并没有同步期待修改的数量(expectedModCount)值,所以会抛异常了。
5.迭代器循环迭代器删除(可靠)
ps:代码中使用了lamba表达式
输出结果:
结果输出正常,这是因为迭代器中的 remove 方法将期待修改的数量(expectedModCount)值进行了同步:
所以,这种删除方法是安全的,推荐使用。
6.迭代器循环集合删除(抛异常)
输出结果:
又是那个并发修改异常,这个示例虽然使用了 Iterator 循环,但删除的时候却使用了 list.remove 方法,同样是有问题的。
7.集合 forEach 方法循环删除(抛异常)
输出结果:
我们一起看下forEach 源码:
forEach 方法的背后其实就是增强for循环,底层即迭代器,所以使用 list.remove 同样抛出
ConcurrentModificationException 异常。
8.Java8新特性 stream流 filter 过滤(可靠)
输出结果:
这个方法即是利用了 Stream 的筛选功能,快速过滤所需要的元素,虽然不是进行集合删除,但达到了同样的目的,这种方法要更简洁优雅。
本文总结了 8 种循环删除 List 元素的方法:
普通 for 循环删除(不可靠)
普通 for 循环提取变量删除(抛异常)
普通 for 循环倒序删除(可靠)
增强 for 循环删除(抛异常)
迭代器循环迭代器删除(可靠)
迭代器循环集合删除(抛异常)
集合 forEach 方法循环删除(抛异常)
stream filter 过滤(可靠)