1. 程式人生 > >List 迴圈遍歷中刪除元素問題二

List 迴圈遍歷中刪除元素問題二

問題一可以看我之前寫的部落格List 迴圈遍歷中刪除元素問題一

問題二主要講的是博主在今天的開發中遇到的一個問題,先來看下是什麼問題讓博主繼上次問題後又寫了問題二。

問題一中講到通過Iterator的remove方法解決連結串列中迴圈刪除元素的問題。來看下簡單的程式碼:

public class ListTest {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
list.add("2"); list.add("3"); list.add("4"); list.add("5"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String s = iterator.next(); if ("4".equals(s)) { iterator.remove(); }
} System.out.println("list:" + list); } }

輸出:list:[1, 2, 3, 5],成功刪除元素4。

但是這種解決方法中隱藏著一個坑。在今天和前端的聯調過程中發現,我們一般從資料庫查詢多條資料時會返回List<?>,?表示具體的實體類,然後通過Iterator遍歷List刪除其中的元素,以下是類似的程式碼:

public class ListTest {

    public static void main(String[] args) {
        List<String>
list = Arrays.asList("1","2","3","4","5"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String s = iterator.next(); if ("4".equals(s)) { iterator.remove(); } } System.out.println("list:" + list); } }

原本以為通過iterator.remove()方法能夠成功刪除元素,但是上述程式碼在控制檯卻報了這麼一個錯:

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:22)

一開始感到很困惑,但是在經過自己debug之後終於發現了問題所在,debug下進入的第一個方法:

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        AbstractList.this.remove(lastRet);
        if (lastRet < cursor)
            cursor--;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException e) {
        throw new ConcurrentModificationException();
    }
}

在執行到AbstractList.this.remove(lastRet);時進入下一個方法:

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    
    /*... 其它方法略...*/

	public E remove(int index) {
	    throw new UnsupportedOperationException();
	}
}

原來此處的ArrayList是一個實現了AbstractList的內部類,並且沒有覆蓋add和remove方法,預設這2個方法是會直接報“UnsupportedOperationException”的。

知道問題原因後,解決方法也就明確了。

public class ListTest {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("1","2","3","4","5");

        List<String> result= new ArrayList<>(list);
        Iterator<String> iterator = result.iterator();
        while (iterator.hasNext()) {
            String s = iterator.next();
            if ("4".equals(s)) {
                iterator.remove();
            }
        }

        System.out.println("list:" + result);
    }
}

通過將list拷貝到一個新的ArrayList中即可解決問題二。

總結:在設計一個對外方法的時候,一點要謹慎處理集合和陣列。因為你永遠不知道傳給你的集合是什麼,也不知道是否會有對此集合有任何其他的不可控的操作。所以在使用客戶端傳遞的集合物件時,最好拷貝一個新集合後再操作。