2

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)
6
  • 2
    Can you add the getRank() method? Commented Oct 7, 2016 at 23:58
  • Added it, sorry about that. Commented Oct 8, 2016 at 0:28
  • Can you add the full stacktrace? Commented Oct 8, 2016 at 0:30
  • Sure, added it, thanks in advance for the help Commented Oct 8, 2016 at 0:44
  • 1
    Some of the code mentioned in your stack trace is missing. Commented Oct 8, 2016 at 0:46

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

That was in fact the problem. I made a copy of the sublist and it is now working as intended. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.