为什么在编辑列表列表时出现java.util.ConcurrentModificationException?

时间:2018-12-22 15:49:51

标签: java

这是我无法真正弄清楚的事情:我正在编写纸牌游戏,以检查需要多少手才能完成游戏。问题是我遇到了一个非常奇怪的ConcurrentModificationException

这是发生了什么:我已经将卡片组建模为卡片列表。我遍历所有卡片组,并始终删除顶层卡片。

(在“玩家”下面的代码中是一个牌组列表。我已经使用我在'Deck'类中创建的split函数将牌组一分为二来创建了该列表)

public static Deck oneHand(List<Deck> players){

    List<Card> hand = new ArrayList<>();

    for (int i = 0; i < players.size(); i++) {
           hand.add(players.get(i).pop()); //The exception seems to be thrown the second time here
    }

    //The hand is being played here
}

这是甲板功能。牌组在构造函数中启动。

public class Deck{

    private List<Card> cards

    public Deck() {
    for (int i = 1; i < 13; i++) {
        for (int j = 0; j < 4; j++) {
            cards.add(new Card(i, Suit.values()[j])); //nice and unique
        }
    }

    Collections.shuffle(cards);
    }

    public Deck(List<Card> cards) {
        this.cards = cards;
    }

    public List<Deck> split(int n){
    if(n > cards.size()){
        throw new IllegalArgumentException("Can only split in max " + cards.size() + " elements.");
    }

    List<Deck> result = new ArrayList<>();
    int part = (int) Math.ceil(cards.size()/n);

    for (int i = 1; i <= n; i++) {
        result.add(new Deck(cards.subList((i-1)*part, Math.min(i*part, cards.size()))));
    }

    return result;
    }


    public Card pop(){
         return cards.remove(0);
    }
}

ConcurrentModificationException被扔到纸牌上。将其删除,但是为什么呢?我没有遍历卡片,是吗?而且我不删除甲板吗?

如果有帮助:我调试并注意到第二个玩家(但不是第一个玩家)抛出异常,这也是最后一个玩家。提前致谢!

1 个答案:

答案 0 :(得分:0)

从您的代码开始,没有Player的实现,给我的印象是您正在共享每个玩家的子列表。

  • 子列表可能只是其所有者列表的视图。
  • 删除子列表上的内容 可能会更改视图。
  • 基于同一视图删除子列表上的内容 可能会抛出ConcurrentModificationException,因为您是第一次使另一个子列表的视图无效。

假设您有一个列表(A,B,C,D):

  • L1 = sublist(0,2)返回[A,B],但可以将其实现为startIndex为0且endIndex为2的视图。因为索引可能无效,实现记住视图的最后一个“状态”。
  • L2 = sublist(2,4)返回[C,D],但可以将其实现为其startIndex为2且endIndex为4的视图。因为该索引可能使实现无效记住视图的最后一个“状态”。
  • L1.remove(index)的意思是view.remove(startIndex + index)。它的工作原理:视图状态现在已更改。
  • L2.remove(index)的意思是view.remove(startIndex + index)。失败:视图状态与子列表不匹配。

TL; DR:,您应该在Player实例中复制子列表。