Java ArrayList刪除特定元素的方法
ArrayList是最常用的一種java集合,在開發中我們常常需要從ArrayList中刪除特定元素。有幾種常用的方法:
最樸實的方法,使用下標的方式:
ArrayList<String> al = new ArrayList<String>(); al.add("a"); al.add("b"); //al.add("b"); //al.add("c"); //al.add("d"); for (int i = 0; i < al.size(); i++) { if (al.get(i) == "b") { al.remove(i); i--; } }
在程式碼中,刪除元素後,需要把下標減一。這是因為在每次刪除元素後,ArrayList會將後面部分的元素依次往上挪一個位置(就是copy),所以,下一個需要訪問的下標還是當前下標,所以必須得減一才能把所有元素都遍歷完
還有另外一種方式:
ArrayList<String> al = new ArrayList<String>(); al.add("a"); al.add("b"); al.add("b"); al.add("c"); al.add("d"); for (String s : al) { if (s.equals("a")) { al.remove(s); } }
此處使用元素遍歷的方式,當獲取到的當前元素與特定元素相同時,即刪除元素。從表面上看,程式碼沒有問題,可是執行時卻報異常:
Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:886) at java.util.ArrayList$Itr.next(ArrayList.java:836) at com.mine.collection.TestArrayList.main(TestArrayList.java:17)
從異常堆疊可以看出,是ArrayList的迭代器報出的異常,說明通過元素遍歷集合時,實際上是使用迭代器進行訪問的。可為什麼會產生這個異常呢?打斷點單步除錯進去發現,是這行程式碼丟擲的異常:
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
modCount是集合修改的次數,當remove元素的時候就會加1,初始值為集合的大小。迭代器每次取得下一個元素的時候,都會進行判斷,比較集合修改的次數和期望修改的次數是否一樣,如果不一樣,則丟擲異常。檢視集合的remove方法:
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 }
可以看到,刪除元素時modCount已經加一,但是expectModCount並沒有增加。所以在使用迭代器遍歷下一個元素的時候,會丟擲異常。那怎麼解決這個問題呢?其實使用迭代器自身的刪除方法就沒有問題了
ArrayList<String> al = new ArrayList<String>(); al.add("a"); al.add("b"); al.add("b"); al.add("c"); al.add("d"); Iterator<String> iter = al.iterator(); while (iter.hasNext()) { if (iter.next().equals("a")) { iter.remove(); } }
檢視迭代器自身的刪除方法,果不其然,每次刪除之後都會修改expectedModCount為modCount。這樣的話就不會丟擲異常
public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }
建議以後操作集合類的元素時,儘量使用迭代器。可是還有一個地方不明白,modCount和expectedModCount這兩個變數究竟是幹什麼用的?為什麼集合在進行操作時需要修改它?為什麼迭代器在獲取下一個元素的時候需要判斷它們是否一樣?它們存在總是有道理的吧
其實從異常的型別應該是能想到原因:ConcurrentModificationException.同時修改異常。看下面一個例子
List<String> list = new ArrayList<String>(); // Insert some sample values. list.add("Value1"); list.add("Value2"); list.add("Value3"); // Get two iterators. Iterator<String> ite = list.iterator(); Iterator<String> ite2 = list.iterator(); // Point to the first object of the list and then, remove it. ite.next(); ite.remove(); /* The second iterator tries to remove the first object as well. The object does not exist and thus, a ConcurrentModificationException is thrown. */ ite2.next(); ite2.remove();
同樣的,也會報出ConcurrentModificationException。
相關文章
- ArrayList元素的刪除(4種函式)函式
- Java ArrayList 查詢、刪除指定元素;排序;遍歷;隨機獲取元素等常用操作Java排序隨機
- Python列表刪除元素的方法有哪些?Python
- 【java】【集合】去除ArrayList中的元素、ArrayList巢狀ArrayListJava巢狀
- PHP從陣列中刪除元素的方法PHP陣列
- Python 中刪除列表元素的三種方法Python
- 在ArrayList的迴圈中刪除元素,會不會出現問題?
- arcgis js:graphicLayer刪除特定的graphicJS
- 建立元素和刪除元素
- Python優雅遍歷字典刪除元素的方法Python
- JS刪除陣列裡的某個元素方法JS陣列
- Java碼農必須掌握的迴圈刪除List元素的正確方法Java
- jQuery刪除元素jQuery
- jQuery 刪除元素jQuery
- HashMap 之元素刪除HashMap
- 重構 001 - 刪除Java的Setter方法Java
- Python刪除列表元素的3種方法,你都會嗎?Python
- Redis刪除特定字首key的優雅實現Redis
- JavaScript刪除陣列元素JavaScript陣列
- 簡單介紹Golang切片刪除指定元素的三種方法Golang
- 刪除內聯元素之間的空隙
- jQuery刪除具有指定文字的li元素jQuery
- Array · 刪除陣列中指定的元素陣列
- 根據陣列的值刪除元素陣列
- PHP 刪除陣列中元素的方式PHP陣列
- JavaScript 刪除陣列指定元素JavaScript陣列
- JavaScript刪除array陣列元素JavaScript陣列
- 運用sed命令高效地刪除檔案的特定行
- STL.vector容器刪除單個元素、部分元素、全部元素
- JavaScript 陣列新增或者刪除元素JavaScript陣列
- JavaScript陣列刪除重複元素JavaScript陣列
- jQuery為元素新增和刪除classjQuery
- JavaScript 刪除陣列重複元素JavaScript陣列
- JavaScript 動態新增與刪除元素JavaScript
- Remove Duplicate Letters 刪除重複元素REM
- ES6刪除字串中重複的元素字串
- 陣列的方法-新增刪除陣列
- JavaScript動態新增或者刪除HTML元素JavaScriptHTML
- jQuery點選按鈕刪除div元素jQuery