Java ArrayList刪除特定元素的方法
ArrayList是最常用的一種java集合,在開發(fā)中我們常常需要從ArrayList中刪除特定元素。
ArrayList是最常用的一種java集合,在開發(fā)中我們常常需要從ArrayList中刪除特定元素。有幾種常用的方法:
最樸實(shí)的方法,使用下標(biāo)的方式:
- ArrayList al = new ArrayList();
- 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--;
- }
- }
在代碼中,刪除元素后,需要把下標(biāo)減一。這是因?yàn)樵诿看蝿h除元素后,ArrayList會(huì)將后面部分的元素依次往上挪一個(gè)位置(就是copy),所以,下一個(gè)需要訪問的下標(biāo)還是當(dāng)前下標(biāo),所以必須得減一才能把所有元素都遍歷完
還有另外一種方式:
還有另外一種方式:
- ArrayList al = new ArrayList();
- 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);
- }
- }
此處使用元素遍歷的方式,當(dāng)獲取到的當(dāng)前元素與特定元素相同時(shí),即刪除元素。從表面上看,代碼沒有問題,可是運(yùn)行時(shí)卻報(bào)異常:
- 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的迭代器報(bào)出的異常,說明通過元素遍歷集合時(shí),實(shí)際上是使用迭代器進(jìn)行訪問的??蔀槭裁磿?huì)產(chǎn)生這個(gè)異常呢?打斷點(diǎn)單步調(diào)試進(jìn)去發(fā)現(xiàn),是這行代碼拋出的異常:
- final void checkForComodification() {
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
- }
modCount是集合修改的次數(shù),當(dāng)remove元素的時(shí)候就會(huì)加1,初始值為集合的大小。迭代器每次取得下一個(gè)元素的時(shí)候,都會(huì)進(jìn)行判斷,比較集合修改的次數(shù)和期望修改的次數(shù)是否一樣,如果不一樣,則拋出異常。查看集合的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
- }
可以看到,刪除元素時(shí)modCount已經(jīng)加一,但是expectModCount并沒有增加。所以在使用迭代器遍歷下一個(gè)元素的時(shí)候,會(huì)拋出異常。那怎么解決這個(gè)問題呢?其實(shí)使用迭代器自身的刪除方法就沒有問題了
- ArrayList al = new ArrayList();
- al.add("a");
- al.add("b");
- al.add("b");
- al.add("c");
- al.add("d");
- Iterator iter = al.iterator();
- while (iter.hasNext()) {
- if (iter.next().equals("a")) {
- iter.remove();
- }
- }
查看迭代器自身的刪除方法,果不其然,每次刪除之后都會(huì)修改expectedModCount為modCount。這樣的話就不會(huì)拋出異常
- 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();
- }
- }
建議以后操作集合類的元素時(shí),盡量使用迭代器。可是還有一個(gè)地方不明白,modCount和expectedModCount這兩個(gè)變量究竟是干什么用的?為什么集合在進(jìn)行操作時(shí)需要修改它?為什么迭代器在獲取下一個(gè)元素的時(shí)候需要判斷它們是否一樣?它們存在總是有道理的吧
其實(shí)從異常的類型應(yīng)該是能想到原因:ConcurrentModificationException.同時(shí)修改異常??聪旅嬉粋€(gè)例子
其實(shí)從異常的類型應(yīng)該是能想到原因:ConcurrentModificationException.同時(shí)修改異常??聪旅嬉粋€(gè)例子
- List list = new ArrayList();
- // Insert some sample values.
- list.add("Value1");
- list.add("Value2");
- list.add("Value3");
- // Get two iterators.
- Iterator ite = list.iterator();
- Iterator 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();
同樣的,也會(huì)報(bào)出ConcurrentModificationException。
責(zé)任編輯:王雪燕
來(lái)源:
codeceo