概述
前几天的京东一面中有个问题,大概意思是:
有一个场景List集合,我向里边加入10个元素
现在我想删除前五个,要求用一次for循环,问问该怎么做到?
我当时想这道题肯定没有那么简单,应该不是常规思路可以解决的。于是,我给出的我的解决思路是,开辟一个集合把后五个元素加入其中,然后覆盖掉原来的集合。显然这个回答面试官是不满意的。终于找个时间我自己测试了一下子。
import java.util.ArrayList;
import java.util.List;
public class Test6 {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("asdf");
list.add("bbb");
list.add("aaa");
list.add("acd");
list.add("da");
list.add("bb");
list.add("yyy");
for (int i = 0; i < list.size(); i++) {
if (i <= 4) {
list.remove(i);
}
}
for (String a:list) {
System.out.println(a);
}
}
}
结果是:
bbb
acd
bb
是不是发现和我们的预期相差甚远,哈哈,没错,我也是一脸懵逼。
下边是我想出来的正确的解决办法,也是网上的正确在集合for循环里删除元素的方法
import java.util.ArrayList;
import java.util.List;
public class Test6 {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("asdf");
list.add("bbb");
list.add("aaa");
list.add("acd");
list.add("da");
list.add("bb");
list.add("yyy");
int sign = 0;
for(int i=0;i<list.size();i++){
list.remove(i);
i--;
sign++;
if (sign == 5){
break;
}
}
for (String a:list) {
System.out.println(a);
}
}
}
结果:
bb
yyy
其实背后的原因也很简单,就是list集合是动态的集合,这个动态是指我在删除一个元素的时候那么这个list集合为了保持正确性,集合的长度就要减一,这个元素后边的元素就要向前移动一个位置,就是这个元素后所有元素的下标减一。所以那句话:‘’for循环只能用来遍历集合,不可以在遍历的同时进行修改和删除。‘’你理解了吗?
--------------------------------------------------------------------------------------------------------------------拓展一下:
讲一下,为什么foreach循环也不能在遍历集合的时候进行删除元素的操作呐?
import java.util.ArrayList;
import java.util.List;
public class Test7 {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("asdf");
list.add("bbb");
list.add("aaa");
list.add("acd");
list.add("da");
list.add("bb");
list.add("yyy");
for (String s:list) {
if (s.contains("a")) {
list.remove(s);
}
}
for (String string:list) {
System.out.println(string + "-----------------");
}
}
}
结果是:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at 秋招.test.Test7.main(Test7.java:28)
深入分析jdk1.8的ArrayList源码的foreach方法
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
重点看这个
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
我们知道list在进行foreach的时候都会生成一个迭代器就是iterator,由这个迭代器来进行遍历的操作。当然删除的时候也要经过这个迭代器的。而迭代器有两个方法在遍历数据的时候要用到的,一个是iterator.hasNext(); //判读是否有下个元素。另一个是item = iterator.next();//下个元素是什么,并把它赋给item。
我们来看一下这两个方法的源码
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();------------------重点看这个
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
这样的话,我们就锁定了modCount != expectedModCount所以抛出了异常,而modCount是指什么呐?expectedModCount又是什么呐?从字面的意思上expectedModCount是期望修改的次数。而modCount是实际的修改的次数。
expectedModCount在生成迭代器的时候就已经生成好了,就是集合的元素大小,而在遍历时删除元素,这个modCount值就会改变,所以为了安全起见抛出了异常。
结语:
希望我的分享对你有所帮助,也欢迎批评指正!
最后
以上就是可耐帅哥为你收集整理的增强的for循环遍历期间删除集合元素的问题的全部内容,希望文章能够帮你解决增强的for循环遍历期间删除集合元素的问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复