簡體   English   中英

在Java中刪除沒有Iterator.remove()的列表項

[英]Remove List Item without Iterator.remove() in Java

我有一個基本的事件管理器設置,該設置可循環訪問偵聽器的鏈接列表以將事件通知他們。 偵聽器都是通過層次結構關聯的(一個控制另一個),在一個特定事件期間,一個對象將從列表中刪除另一個。 刪除的對象位於層次結構的底部,沒有自己的子級。

因此,我目前正在獲取ConcurrentModificationException,並且由於我要刪除的對象不是當前迭代的對象,因此無法使用iterator和iterator.remove()。

有什么干凈的方法可以刪除此對象? 我想避免對子對象進行重組以使其可重用,因為這會破壞我的許多測試套件,但是我寧願擁有高質量的代碼。 我在此項目上使用Java 7,無法升級到Java 8。

下面是示例代碼,以及我想出的唯一想法。 該代碼並不精確,僅用於說明我當前設置的結構。

活動管理器通知:

public void notifyListeners(Object sender, EventArgs args) {
    for (Listener l : listeners) {
        l.notify(sender, args);
    }
}

偵聽器示例:

public class Listener {

    ...

    private Listener myChild;

    public void notify(Object sender, EventArgs args) {
        if (myChild != null) {
            eventManager.removeListener(myChild);
        }

        mychild = new Child();
        eventManager.addListener(myChild);
    }

    ...
}

我的想法(未經測試):

public void notifyListeners(Object sender, EventArgs args) {
    int listSize = listeners.size();

    for (int i = 0; i < listSize; i++) {
        l.notify(sender, args);

        if (listeners.size() != listSize) {
            listSize = listeners.size();
            i = listeners.indexOf(l);
        }
    }
} 

work for now, this could easily break in the future. 雖然我的想法目前行得通,但將來很可能會打破。 而且它也不安全。

謝謝您的幫助。

您可以在開始遍歷偵聽器以處理事件時復制偵聽器的集合。 例如:

for(Listener l : new ArrayList<Listener>(listeners)) {

您將不得不復制列表,但這樣for循環將在與您以后修改的偵聽器不同的偵聽器集合上工作。

不行 JavadocIterator.remove() (部分),

如果在迭代進行過程中以其他方式(而不是通過調用此方法)修改了基礎集合,則未指定迭代器的行為。

您可以利用CopyOnWriteArrayList,檢查以下代碼。

    import java.util.List;
    import java.util.ArrayList;
    import java.util.concurrent.CopyOnWriteArrayList;
    public  class  Test{

       List<String> stringList = new CopyOnWriteArrayList<String>();

       public void test(){
           for(int i=0;i<100;i++){
               stringList.add("item"+i);
           }

           new IteratorThread().start();
           new RemoveThenAddThread().start();
       }
       class IteratorThread extends Thread{
           public void run(){
               while(true) {
                   for (String l : stringList) {
                       System.out.println(l);
                       //DO SOMETHING
                       try {
                           Thread.sleep(10);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }
           }
       }

        class RemoveThenAddThread extends Thread{
            public void run(){

                while(true) {
                    stringList.remove(0);
                    stringList.add("string item");

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }


        public static void main(String[] args) 
        {
            new Test().test();
        }
    }

我看了Frank Zheng提到的CopyOnWriteArrayList,看看這是否是我真正想要的。 雖然不是,但這確實使我找到了ConcurrentLinkedQueue,它可以完美地處理我的情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM