Java中如何正確遍歷刪除List中的元素
for循環(huán)索引刪除
刪除長度為4的字符串元素。
List<String> list = new ArrayList<String>();
list.add("AA");
list.add("BBB");
list.add("CCCC");
list.add("DDDD");
list.add("EEE");
?
for (int i = 0; i < list.size(); i++) {
if (list.get(i).length() == 4) {
list.remove(i);
}
}
System.out.println(list);
}
實際上輸出結(jié)果:
[AA, BBB, DDDD, EEE]
DDDD 竟然沒有刪掉!
原因是:刪除某個元素后,list的大小size發(fā)生了變化,而list的索引也在變化,索引為i的元素刪除后,后邊元素的索引自動向前補位,即原來索引為i+1的元素,變?yōu)榱怂饕秊?code>i的元素,但是下一次循環(huán)取的索引是i+1,此時你以為取到的是原來索引為i+1的元素,其實取到是原來索引為i+2的元素,所以會導致你在遍歷的時候漏掉某些元素。
比如當你刪除第1個元素后,繼續(xù)根據(jù)索引訪問第2個元素時,因為刪除的關系后面的元素都往前移動了一位,所以實際訪問的是第3個元素。不會報出異常,只會出現(xiàn)漏刪的情況。
foreach循環(huán)刪除元素
for (String s : list) {
if (s.length() == 4) {
list.remove(s);
?
}
}
System.out.println(list);
如果沒有break,會報錯:
java.util.ConcurrentModificationException at java.util.ArrayListItr.checkForComodification(ArrayList.java:911)atjava.util.ArrayListItr.checkForComodification(ArrayList.java:911) at java.util.ArrayListItr.checkForComodification(ArrayList.java:911)atjava.util.ArrayListItr.next(ArrayList.java:861) at com.demo.ApplicationTest.testDel(ApplicationTest.java:64) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
報ConcurrentModificationException錯誤的原因:
看一下JDK源碼中ArrayList的remove源碼是怎么實現(xiàn)的:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
一般情況下程序會最終調(diào)用fastRemove方法:
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
在fastRemove方法中,可以看到第2行把modCount變量的值加一,但在ArrayList返回的迭代器會做迭代器內(nèi)部的修改次數(shù)檢查:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
而foreach寫法是對實際的Iterable、hasNext、next方法的簡寫,因為上面的remove(Object)方法修改了modCount的值,所以才會報出并發(fā)修改異常。
阿里開發(fā)手冊也明確說明禁止使用foreach刪除、增加List元素。
迭代器Iterator刪除元素
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
if(iterator.next().length()==4){
iterator.remove();
}
}
System.out.println(list);
[AA, BBB, EEE]
這種方式可以正常的循環(huán)及刪除。但要注意的是,使用iterator的remove方法,而不是List的remove方法,如果用list的remove方法同樣會報上面提到的ConcurrentModificationException錯誤。
總結(jié)
無論什么場景,都不要對List使用for循環(huán)的同時,刪除List集合元素,要使用迭代器刪除元素。
到此這篇關于Java中如何正確遍歷刪除List中的元素的文章就介紹到這了,更多相關Java遍歷刪除List內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java實現(xiàn)調(diào)用對方http接口得到返回數(shù)據(jù)
這篇文章主要介紹了Java實現(xiàn)調(diào)用對方http接口得到返回數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
java 實現(xiàn)取int型的第二個字節(jié)的數(shù)
這篇文章主要介紹了java 實現(xiàn)取int型的第二個字節(jié)的數(shù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01

