網上關於集合類型使用Iterator遍歷須要注意的事項想必你們都已熟知,若是你想要遍歷的時候刪除集合中的元素,若是你像下面這樣寫,是會報錯的!java
public void testRemove() { Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ String next = iterator.next(); if("1".equals(next)){ list.remove(next);//引起ConcurrentModificationException } } }
異常以下:dom
Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) at java.util.ArrayList$Itr.next(ArrayList.java:859) at list.ListTest.testRemove(ListTest.java:40) at list.ListTest.main(ListTest.java:33)
Iterator迭代器採用fail-fast
機制,一旦在迭代過程當中檢測到該集合已經被修改,程序會當即引起:ConcurrentModificationException
異常,以免共享資源而引起的潛在問題。測試
正確的寫法是使用iterator提供的remove方法:ui
public void testCorrectRemove(){ Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ String next = iterator.next(); if("1".equals(next)){ iterator.remove(); // 使用迭代器的remove } } System.out.println(list); }
可是今天在測試的時候遇到一個問題,個人代碼以下:this
public static void main(String[] args) { // 注意這裏建立list的方式 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()) { Integer num = iterator.next(); System.out.println(num); if (num == 2) { iterator.remove(); } } System.out.println(list); }
引發了以下異常:code
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.remove(AbstractList.java:161) at java.util.AbstractList$Itr.remove(AbstractList.java:374) at list.ListTest.main(ListTest.java:28)
這就奇怪了,爲何這個List不行呢?element
public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }
明明建立的就是一個ArrayList啊,事實上,此ArrayList非彼ArrayList,咱們能夠跟進去談談究竟:資源
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; ArrayList(E[] array) { a = Objects.requireNonNull(array); } }
這個ArrayList是定義在Arrays類中的一個靜態內部類,和我平時使用的並非同一個!而且,咱們能夠看看其中Iterator的remove方法:rem
public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { // 調用原本的remove方法 AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } }
!它調用了本類的remove方法,而remove方法並無具體實現,而是拋出了異常:it
public E remove(int index) { throw new UnsupportedOperationException(); }
而咱們平時的ArrayList的remove方法的實現是下面這個樣子的:
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); 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 return oldValue; }
這下子,恍然大悟,原來是這樣,瞭解這個以後,修改起來就相對簡單了,咱們把它轉化爲咱們熟知的ArrayList就行了:
public static void main(String[] args) { // 轉化爲ArrayList List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()) { Integer num = iterator.next(); System.out.println(num); if (num == 2) { iterator.remove(); } } System.out.println(list); }
先看個例子:
public void testRemoveNumber() { List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); list.remove(3); System.out.println(list); }
若是程序執行,結果會是如何呢?答案以下:
[1, 2, 3, 5] // 移除了index = 3的元素,而不是移除值爲3的元素
若是我就是想移除值爲3的元素呢?能夠使用Integer包裝一下。
public void testRemoveNumber() { List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); list.remove(new Integer(3)); System.out.println(list); }
結果就變成了:
[1, 2, 4, 5] // 移除了值爲3元素
二者區別在於:調用的remove方法不一樣。前者調用的是:remove(int index)
,後者調用的是remove(Object o)
。所以,若是咱們想要移除某個值,且這個值是數值的時候,咱們須要注意一下這個問題。