簡體   English   中英

避免靜態集合的ConcurrentModification的好習慣

[英]Good practice to avoid ConcurrentModification of static collection

考慮玩家等級...當玩家加入游戲(創建對象)時,它會檢查已經加入的同名玩家...

public class Player {

    private static List<Player> players = new ArrayList<>();
    private String name;

    public Player(String name) {
        this.name = name;

        for (Player otherPlayer : players) { // Iterating static field
            if (otherPlayer.name.equalsIgnoreCase(name)) {
                otherPlayer.quit("Somebody with the same name joined the game");
            }
        }
    }

    public void quit(String message) {
        players.remove(this); // Modifying static field
        Server.disconnect(this, message);
    }
}

我知道Iterator可以處理這個問題,但我們並不總是知道外部方法中的公共靜態字段會發生什么,以及何時使用foreach以及何時使用Iterator ...

這個問題有什么好的做法嗎?

第一個也是更重要的良好做法稱為關注點分離 如下所示:Player類應該為單個玩家建模。

您正在混合作為播放器的責任並在一個地方管理整個Player對象集。 不要那樣做!

這兩件事根本就不屬於一體。 在這個意義上:應該有一個PlayerManager例如類, 知道所有玩家。 而且忘了使用像這樣的static字段。 因為這會在班級的不同方面之間產生超緊密耦合。 例如,當您需要多個玩家列表時會發生什么? 如果您有這么多玩家想要根據某些屬性在桶中組織它們怎么辦?

除此之外,直接的答案是:而不是立即從列表中刪除對象 - 將它們收集到第二個playersToBeDeleted列表中。 迭代第一個列表之后,只需使用players.removeAll(playersToBeDeleted)

並談論好的做法:仔細考慮你是否真的想要使用列表 - 或者如果Set不是更好的選擇。 列表總是暗示訂單,而且,它們允許重復添加相同的對象。 而Set則免費為您提供“獨特元素”語義!

我看到你正在嘗試調用list.remove(entry)方法,同時仍在for-each塊中。 不要那樣做。

當需要時,使用Iterator而不是for-each構造:

  1. 刪除當前元素。 for-each構造隱藏了迭代器,因此您無法調用remove。 因此,for-each構造不可用於過濾。
  2. 並行迭代多個集合。

請注意, Iterator.remove是在迭代期間修改集合的唯一安全方法; 如果在迭代進行過程中以任何其他方式修改基礎集合,則行為未指定。

暫無
暫無

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

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