月薪15k的小党挂在了list.remove()上
图片来源:pixabay.com
java4all原创,欢迎关注
摘要:基友小党去面试,挂在了list.remove()上。这是一个见过就再也不会忘记的面试题,没见过的话,多半会挂掉。
面试官:在一个集合中,有几个随机字符串,有些含有a,有些没有a,用普通for循环遍历,移除含有a字符的字符串,示例如下,请问最终的打印输出结果是?
public static void main(String[] args) {
//建立一个list集合,里面有5个元素含有“a”,3个不含有“a”
List<String> list = new ArrayList<>();
list.add("abc");
list.add("anc");
list.add("amg");
list.add("agf");
list.add("omg");
list.add("aig");
list.add("gme");
list.add("wbe");
//遍历集合,移除含有“a”的元素
for(int i = 0; i < list.size();i++){
String str = list.get(i);
if(str.contains("a")){
list.remove(i);
}
}
//打印,看结果
for (Object st : list) {
System.out.print(st+" ");
}
}
小党:打印结果为:
omg gme wbe
面试官:为什么?怎么分析的?
小党:遍历的过程中,含有a字符的字符串都移除了,剩下的都是没有a字符串的。
面试官:再想想。
小党:。。。。。。
面试官:今天先到这里,回去等通知吧。(这都不会,滚犊子吧)
这个问题,遇到过的人,分分钟分析出结果,但是如果,你恰巧没遇到过,也没自己想过这个问题,那很可能会卡死在这里,因为初学者或者没碰到过的开发者,压根没想过这个list.remove()这个简单方法有任何问题。
实际结果为:
anc agf omg gme wbe
我们发现,结果中,竟然有两个字符串中含有a,它不是应该已经被移除了吗?为什么会这样呢?
重点来了!
在list集合遍历的时候,每一次循环,指针都会向后移动一位(理解为i从0开始,每次都会后移一位),但是,如果有元素被删除了,那后面的所有元素都会顺次向前移动一位(0索引的元素没了,那后面的就会补过来啊),所以每次操作结果如下表:
指针一直在向后跑,当有元素移除,后面的集体前移时,就恰好会有漏网之鱼,指针没有指向过它,图上红色的,就漏掉了。
那么,这个问题,怎么处理呢?
很简单,当有元素被移除时,我们把指针前移一位,弥补一下这个偏差,就不会有漏掉的了,代码如下,仅仅就是加了一句: i--;
//遍历集合,移除含有“a”的元素
for(int i = 0; i < list.size();i++){
String str = list.get(i);
if(str.contains("a")){
list.remove(i);
i--;
}
}
此时,再看一下指针移动和每次操作的过程:
由于每次有元素被删除时,强行把指针回退一位,那么漏网之鱼就会被指针扫过,判断有a,直接移除。
(注意i--的位置,当没有移除元素时,指针是没有强制回退的)
此时,执行代码,结果为:
omg gme wbe
此问题,还可以有第二种方法处理,倒着遍历:
关键部分代码如下:
for(int j = list.size()-1;j >= 0;j-- ){
String str = (String)list.get(j);
if(str.contains("a")){
list.remove(j);
}
}
这样也可以避免这个问题。
希望你看到这篇文章后,再也不要在这个小问题上卡住。
对文章内容有疑问或者不同的见解,欢迎关注公众号java4all,或添加我的微信w1186355422一起交流讨论。
与其相忘江湖,不如点赞关注