ArrayList使用的坑

其實這也是老生常談的問題,但奇怪的的是最近幾年在開發時都沒遇到過,所以今天是個特殊的日子。

場景:比如後臺返回一個列表,值可能爲空,前臺自己過濾

僞代碼

        ArrayList<People> strings = new ArrayList<People>();
        strings.add(new People(""));
        strings.add(new People(""));
        strings.add(new People(""));
        strings.add(new People("a"));

        for (int i = 0; i < strings.size(); i++) {
            People people = strings.get(i);
            if (people.name == null || people.name == "") {
                strings.remove(people);
            }
            System.out.println(i + "----" + people.name + "------" + strings.size());
        }


0----------3
1----------2
strings.get(i)==
strings.get(i)==a

有一個符合條件的沒刪掉!!!

冷靜下,看下源碼

public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }


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
    }

主要是因爲內部size做了-1的操作,遍歷到下一節點時,index其實相當於把第二個空值跳過了直接刪除了第三個。這種情況可以使用迭代器操作

  ListIterator<People> it = strings.listIterator();
        while (it.hasNext()) {
            People people = it.next();
            if (people.name == null || people.name == "") {
                it.remove();
            }
            System.out.println( people.name + "------" + strings.size());
        }

------3
------2
------1
a------1
strings.get(i)==a

順便看看看其他坑,使用for each遍歷

 for (People people : strings) {
            if (people.name == null || people.name == "") {
                strings.remove(people);
            }
            System.out.println(people.name + "------" + strings.size());
 }






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)

報了個錯,因爲foreach遍歷本質就是利用iterater的hasNext和next結合進行遍歷 看這

iterater在創建時會把modCount賦值給expectedModCount,但增刪的時候不會更新expectedModCount。

現在遇到這兩種情況,應該還會有其他的,比如老版本中調用remove可能造成下標越界,因爲size沒有實時調整,所以有個不成文的規定,循環操作裏儘量不要做remove操作,哈哈

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章