您好,登錄后才能下訂單哦!
小編給大家分享一下HashMap和List中怎么遍歷刪除元素,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
相信大家對集合遍歷再熟悉不過了,這里總結一下HashMap和List的遍歷方法,以及它們該如何實現遍歷刪除。
這里對于每種遍歷刪除出現的問題的原因都給出了詳解!
(一)List的遍歷方法及如何實現遍歷刪除
我們造一個list出來,接下來用不同方法遍歷刪除,如下代碼:
List<String> list= new ArrayList<String>(); famous.add("zs"); famous.add("ls"); famous.add("ww"); famous.add("dz");
1、for循環遍歷list:
for(int i=0;i<list.size();i++){ if(list.get(i).equals("ls")) list.remove(i); }
這是一種很常見的遍歷方式,但是使用這種遍歷刪除元素會出現問題,原因在于刪除某個元素后,list的大小發生了變化,而你的索引也在變化,所以會導致你在遍歷的時候漏掉某些元素。比如當你刪除第一個元素后,繼續根據索引訪問第二個元素后,因為刪除的原因,后面的元素都往前移動了以為,所以實際訪問的是第三個元素。因此,這種遍歷方式可以用在讀取元素,而不適合刪除元素。
2、增強for循環:
for(String x:list){ if(x.equals("ls")) list.remove(x); }
這也是一種很常見的遍歷方式,但是使用這種遍歷刪除元素也會出現問題,運行時會報ConcurrentModificationException異常
其實增強for循環是java語法糖的一種體現,如果大家通過反編譯得到字節碼,那么上面這段代碼的內部實現如下所示:
for(Iterator<String> it = list.iterator();it.hasNext();){ String s = it.next(); if(s.equals("madehua")){ list.remove(s); } }
下面就解釋為什么會報ConcurrentModificationException異常。分析Iterator的源代碼,重點分析整個調用該過程中的
函數(hasNext和remove):
private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; // size為集合中元素的個數 } 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]; } /* 此方法并沒被調用,只是調用List.remove方法 public void remove() { checkForComodification(); try { ArrayList.this.remove(lastRet); // size字段減1 cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } */ final void checkForComodification() { // 檢查修改和當前版本號是否一致,不一致則拋出異常 if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } // List.remove @Override public boolean remove(Object object) { Object[] a = array; int s = size; if (object != null) { for (int i = 0; i < s; i++) { if (object.equals(a[i])) { System.arraycopy(a, i + 1, a, i, --s - i); a[s] = null; // Prevent memory leak size = s; modCount++; // 核心代碼:修改了版本號。這樣當checkForComodification的時候,modCount值就和expectedModCount不同 return true; } } } else { for (int i = 0; i < s; i++) { if (a[i] == null) { System.arraycopy(a, i + 1, a, i, --s - i); a[s] = null; // Prevent memory leak size = s; modCount++; return true; } } } return false; }
接下來梳理一下流程,這時候你就會發現這個異常是在next方法的checkForComodification中拋出的。拋出的原因是
modCount !=expectedModCount。這里的modCount是指這個list對象從呢我出來到現在被修改的次數,當調用list
的add或者remove方法的時候,這個modCount都會自動增減;iterator創建的時候modCount被復制給了
expectedModcount,但是調用list的add和remove方法的時候不會同時自動增減expectedModcount,這樣就導致
兩個count不相等,從而拋出異常。大家如果理解了上面的執行流程,以后碰到類似這種問題,比如如果刪除的是倒數
第二個元素卻不會碰到異常。就會知道為什么了。
3、iterator遍歷刪除
Iterator<String> it = list.iterator(); while(it.hasNext()){ String x = it.next(); if(x.equals("del")){ it.remove(); } }
這種方式是可以正常遍歷和刪除的。但是你可能看到上面代碼感覺和增強for循環內部實現的代碼差不多,其實差別就在于上面使用一個使用list.remove(),一個使用it.remove()。
(二)HashMap的遍歷刪除及如何實現遍歷刪除
一樣我們先造一個hashmap出來,如下
private static HashMap<Integer, String> map = new HashMap<Integer, String>();; public static void main(String[] args) { for(int i = 0; i < 10; i++){ map.put(i, "value" + i); } }
1、第一種遍歷刪除:
for(Map.Entry<Integer, String> entry : map.entrySet()){ Integer key = entry.getKey(); if(key % 2 == 0){ System.out.println("To delete key " + key); map.remove(key); System.out.println("The key " + + key + " was deleted"); }
這種遍歷刪除依舊會報ConcurrentModificationException異常,
2、第二種遍歷刪除:
Set<Integer> keySet = map.keySet(); for(Integer key : keySet){ if(key % 2 == 0){ System.out.println("To delete key " + key); keySet.remove(key); System.out.println("The key " + + key + " was deleted"); } }
這種遍歷刪除依舊會報ConcurrentModificationException異常,
3、第三種遍歷刪除:
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator(); while(it.hasNext()){ Map.Entry<Integer, String> entry = it.next(); Integer key = entry.getKey(); if(key % 2 == 0){ System.out.println("To delete key " + key); it.remove(); System.out.println("The key " + + key + " was deleted"); } }
這種遍歷是OK的
分析上述原因,如果大家理解了List的遍歷刪除,那么感覺HashMap的遍歷刪除是不是有類似之處啊。下面就分析一下原因:
如果查詢源代碼以上的三種的刪除方式都是通過調用HashMap.removeEntryForKey方法來實現刪除key的操作。
在removeEntryForKey方法內知識一場了key modCount就會執行一次自增操作,此時modCount就與expectedModCOunt不一致了
,上面三種remove實現中,只有第三種iterator的remove方法在調用完removeEntryForKey方法后同步了expectedModCount值與
modCount相同,所以iterator方式不會拋出異常。最后希望大家遇到問題到查詢源代碼,它會給你最好的解釋!
以上是“HashMap和List中怎么遍歷刪除元素”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。