Rumple Rumple - 2 months ago 6
Java Question

ConcurrentModificationException when attempting to get an element from a List

So I am trying to create a simple Card game and to do this I have created a Player class that holds a name and the Player's hand.

public class Player {
private List<Card> hand;
private String name;

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

public void drawHand(List<Card> hand){
System.out.println(this.name + " draws a hand.");
this.hand = hand;
}
public String throwingError(){
Card c = this.hand.get(0);
return c.getRank();
}
}


And here is the Engine running the game

public static void main(String[] args) {
int numberOfPlayers = Integer.parseInt(args[0]);
players = new Player[numberOfPlayers];
deck = createDeck();
for(int i = 0; i < numberOfPlayers; i++){
players[i] = new Player("Player" + (i+1));
}

for(Player player : players){
List<Card> hand = deck.dealHand();
player.drawHand(hand);
}
String cardRank = players[turn - 1].throwingError();
}


The code is throwing a ConcurrentModificationException when it gets to the last line of the main function, which baffles me since no elements are being iterated or deleted from the hand field in the Player class.

The getRank() method is part of a different class called Card. It's a simple getter

public String getRank() {
return rank;
}


And here is the stack trace:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231)
at java.util.ArrayList$SubList.listIterator(ArrayList.java:1091)
at java.util.AbstractList.listIterator(AbstractList.java:299)
at java.util.ArrayList$SubList.iterator(ArrayList.java:1087)
at java.util.AbstractCollection.toString(AbstractCollection.java:454)
at java.lang.String.valueOf(String.java:2981)
at java.io.PrintStream.println(PrintStream.java:821)
at Player.getRank(Player.java:22)
at GameEngine.nextTurn(GameEngine.java:32)
at GameEngine.main(GameEngine.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Answer

In this code:

for(Player player : players){
    List<Card> hand = deck.dealHand();
    player.drawHand(hand);
}

your dealHand() method is returning a sublist in each iteration, while at the same time adding to the backing list. This is a structural modification of the backing list and, as the Javadoc for sublist() says, the behaviour of methods of the sublist is undefined after a structural modification of the backing list. Thus, the get() operation on the sublist throws.

Either create the whole list in one go and then divide it into sublists, or return copies of each sublist.