首頁 > 軟體

ArrayList和JSONArray邊遍歷邊刪除到底該如何做

2022-12-23 14:01:05

話題看起來有點老生了,但是加入JSONArray還是有很多新意

ArrayList

方式1:索引遍歷

        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3456);
        list.add(3456);
        list.add(4);
        for(int i =0; i < list.size(); i++) {
            if(list.get(i) == 3456) {
                list.remove(i);
            }
        }
    
        System.out.println(list);

沒有異常,有輸出結果[1, 2, 3456, 4],顯然是不對的,沒有把第二個3456刪除掉,問題比較明顯,就是每當刪除一個條目底層就會有一次資料移動,即被刪除條目下一個索引資料佔據了被刪除條目的位置,進入到下一輪遍歷時恰好跳過了原來的下一個條目,就出現了上述的錯誤現象。所以此種遍歷方式是不正確的。

方式2:for each遍歷 

        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3456);
        list.add(3456);
        list.add(4);
        /*for(int i =0; i < list.size(); i++) {
            if(list.get(i) == 3456) {
                list.remove(i);
            }
        }*/
        for(Integer i: list) {
            if(i == 3456) {
                list.remove(i);
            }
        }
        System.out.println(list);

直接報出異常了:

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)

所以此種方式必然不行了。

方式3:迭代器遍歷

        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3456);
        list.add(3456);
        list.add(4);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            if(iterator.next() == 3456) {
                iterator.remove();
            }
        }
        System.out.println(list);

執行結果,完全正確[1, 2, 4]。這也是最推薦的方式。

當然,除了第3種方式外,還有2種可以考慮的方式:

方式4. 不刪除,而是new一個新的list的將其中符合條件的新增到新的list,其實就實現了刪除,還是比較穩妥的方式。

方式5.再一種就是對方式1的改進,一旦滿足條件執行了刪除,就將index--,這樣也是可以實現的,只是很彆扭。

JSONArray

首先,通過JSONArray的原始碼看下,其中與ArrayList的關聯,進入JSONArray類檢視remove的程式碼:

private final List<Object> list;
    public JSONArray() {
        this.list = new ArrayList();
    }
   
 public boolean remove(Object o) {
        return this.list.remove(o);
    }

可以看到,底層就是呼叫的ArrayList的remove方法,那麼據此可以推斷方式1,2也會各自存在同樣的問題。

那麼方式3是不是就完全ok了?

JSONObject o1 = new JSONObject();
        o1.put("key", 324);
 
        JSONObject o2 = new JSONObject();
        o2.put("key", 325);
 
        JSONObject o3 = new JSONObject();
        o3.put("key", 325);
 
        JSONObject o4 = new JSONObject();
        o4.put("key", 327);
 
        JSONArray ja =  new JSONArray();
        ja.add(o1);
        ja.add(o2);
        ja.add(o3);
        ja.add(o4);
 
        Iterator<Object> o = ja.iterator();
        while (o.hasNext()) {
            JSONObject jo = (JSONObject) o.next();
            if(jo.getIntValue("key") == 325) {
                //ja.remove(jo); //不要用這種方式刪除,會報出ConcurrentModificationException
                o.remove(); //這種方式OK的
            }
        }
 
        System.out.println(ja);

執行結果[{"key":324},{"key":327}]是完全正確的,只是這裡有一點需要注意的是儘管迴圈用了iterator,那麼刪除的時候也要用迭代器即o.remove()而不是ja.remove(jo),否則還是會有異常的。

此外,對應的方式4,5在這裡也是適用的,尤其是方式4,也是不錯的方案。

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com