對List遍歷過程中添加和刪除的思考
平時開發過程中,不少開發者都遇到過一個問題:在遍歷集合的的過程中,進行add或者remove操作的時候,會出現2類錯誤,包括:
java.util.ConcurrentModificationException for in遍歷過程中add/remove導致的錯誤
java.lang.IndexOutOfBoundsException 越界錯誤,for循環的時候刪除元素。
最佳實踐
add操作:利用原生的for循環。remove操作利用foreach操作。如下所示:
//OK,利用 iterator 和 其remove 方法
@Test
public void testIteratorRemove2() {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if ("3".equals(iterator.next())) {
iterator.remove();
}
}
System.out.println(list);
}
//OK 利用for循環。
@Test
public void testForAdd() {
for (int i = 0, length = list.size(); i < length; i++) {
if (list.get(i).equals("2")) {
list.add("2");
}
}
}
經典錯誤1
如下代碼本意是:通過iterator的方式從頭到尾變遍歷list中的元素。
@Test
public void testIteratorRemove2() {
while (list.iterator().hasNext()) {
System.out.println(list.iterator().next());
}
}
但是該段代碼永遠都會輸出 list的第一元素,為什么?關鍵錯誤在鏈式寫法上:
while (list.iterator().hasNext()) {}
每次循環時候先調用了list.iterator() 在該方法中每次都是重新new了一個新的對象
public Iterator<E> iterator() {
return new Itr();
}
所以每一次都是一個新的遍歷對象,所以輸出第一個元素。
那么為什么每次都要new一個新的Itr()?我猜想應該是為了並發的讀,每次讀的都是一份獨立的數據,避免多個並發讀的時候,出現當前指針問題。
處理辦法:將list.iteraotr() 放在外面即可,保證循環中循環的是1個對象。
@Test
public void testIteratorRemove2() {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if ("3".equals(iterator.next())) {
iterator.remove();
}
}
System.out.println(list);
}
經典錯誤2
// 死循環
@Test
public void testForAdd2() {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals("3")) {
list.add("3");
}
}
}
當if條件滿足的時候,該方法永遠不會結束,為什么?
對於for循環 for (int i = 0; i < list.size(); i++)有3個部分,第一個部分為初始化,只執行一次。第二個部分每次都會執行,第三個部分也是每次都會執行。
上述問題的第二步會導致無限循環:因為for中每一次循環都會在list添加了一個元素,每次步進為1,內部元素也是每次都加1.
如何處理該問題: list.size()放在第一部分,第一部分只初始化一次。
//OK 利用for循環。
@Test
public void testForAdd() {
for (int i = 0, length = list.size(); i < length; i++) {
if (list.get(i).equals("2")) {
list.add("2");
}
}
}
經典錯誤3
//java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
@Test
public void testForRemove() {
for (int i = 0, length = list.size(); i < length; i++) {
if (list.get(i).equals("3")) {
list.remove("3");
}
}
}
該錯誤在list.add("3")的時候就不會發生該錯誤,具體原因是什么?
Liu CF:轉載請保留原文鏈接,3Q!