4 Replies Latest reply: Mar 4, 2008 10:00 PM by 807591 RSS

    for each loops and ConcurrentModificationException

    807591
      I have a method changeWorld() that is supposed to call a single function on each element of an ArrayList. I've read the API on this exception and this is not a multithreaded application, nor am I modifying the ArrayList itself during the for...each loop.
      public void changeWorld() {
                ArrayList<Segment> snakeSegs = snake.getSnake();
                for (Segment s : snakeSegs){
                     s.move();
                }
                gameView.somethingChanged();
                
           }
      And then the move method:
      public void move(){
              
                lengthOfSnake = model.getSnake().snakeLength();
                System.out.println("Current snake length: " + lengthOfSnake);
                curMoveIter++;
                if (curMoveIter % lengthOfSnake == 0){
                      model.getBoard()[gridx][gridy] = "background";
                }
                
                gridx = gridx+xVel;
                //System.out.println("GridX: " + gridx);
                gridy = gridy+yVel;
              //System.out.println("GridY: " + gridy);
                
              if (gridx > 18){
                  gridx = 18;
                  xVel = -xVel;  // reverse direction (bounce of right wall)
              }
              else if(gridx < 1){
                  gridx = 1;
                  xVel = -xVel;
              }
              if(gridy > 18){
                  gridy = 18;
                  yVel = -yVel;
              }
              else if (gridy < 1){
                  gridy = 1;
                  yVel = -yVel;
              }
              
              model.getBoard()[gridx][gridy] = "segment";
              
              System.out.println("Segment's position: " + gridx + "," + gridy);
              if (detectFood()){
                   model.getBoard()[f.getX()][f.getY()] = "segment";
                   model.makeFood();
                   f = model.getFood();
                   model.setScore(model.getScore() + 10);
                   model.addSnakeSegment(1);
                   System.out.println("Score: " + model.getScore() + "\nFood has been eaten.\nNew food at " + f.getX() + "," + f.getY());
              }
          }
      The exception is thrown at the beginning of the for loop in the changeWorld() method, and only happens if there is more than 1 Segment object in the snakeSegs ArrayList. Should I just use a regular for loop with an index number to cycle through the snakeSegs or what? Thanks!
        • 1. Re: for each loops and ConcurrentModificationException
          jschellSomeoneStoleMyAlias
          this is not a multithreaded application
          The Sun VM is always multi-threaded.

          And if you are using a GUI you are using at least two threads yourself.
          • 2. Re: for each loops and ConcurrentModificationException
            807591
            Oh ok, thanks for that. Well even if I am using a GUI, neither of these methods have anything to do with it, at least as far as I know. So as I understand it that still wouldn't have an effect on the thread I'm using to go through this ArrayList. Why else would I be getting this exception?
            • 3. Re: for each loops and ConcurrentModificationException
              807591
              You are not giving us enough information. Post all of your code. We don't know where the result "snake.getSnake()" comes from. And basically anything in the move() method could be modifying the list. But we can't tell because we don't know what any of the stuff does or how they are related. Like what type is "model"? What type is "snake"? and what do model's methods "getSnake()", "getBoard()", "makeFood()", "getFood()", "getScore()", "addSnakeSegment(1)" do? I bet one of these things does something to the original list.
              • 4. Re: for each loops and ConcurrentModificationException
                807591
                Well I thought I had given enough... I'm working on a Snake game, if you can't tell, and obviously it is still a work in progress, but here is what I've got. "model" is a reference to an object called GameModel, which contains most of the data for the game (or so I think). "snake" is a Snake object, which is basically an ArrayList of Segments (another object). The variable lengthOfSnake is just grabbing the number of segments in the current snake. Here's the code for the GameModel class:
                import java.awt.geom.*;
                import java.util.ArrayList;
                import javax.swing.*;
                
                
                public class GameModel {
                
                     private GameView gameView;
                     
                     private ArrayList<Segment> segments = new ArrayList<Segment>();
                     private Food currentFoodItem;
                     public String[][] board;
                     private int score;
                     public Snake snake;
                     
                     
                     public GameModel() {
                          
                          // create the objects you want in the game
                          // you will need to create some new classes for most/all of the objects
                          board = new String[20][20];
                          makeBoard();
                          makeFood();
                          score = 0;
                          snake = new Snake(this, gameView);
                     }
                     
                     /*
                      * This main method exists only for debugging purposes and is not used in the full game
                      */
                     public static void main(String[] args){
                          GameModel gm = new GameModel();
                          gm.makeBoard();
                          for (int i=0; i<19; i++){
                               for (int w=0; w<19; w++){
                                    System.out.print(gm.board[w] + " ");
                               }
                               System.out.println();
                          }
                          
                     }
                     
                     /*
                     * This method creates an 20x20 "board" that everything exists in data-wise
                     * The paintComponents method in GamePanel should read from this array and create objects based on the strings
                     */
                     public void makeBoard() {

                          fillBoard();
                          System.out.println("Filled board.");
                          
                          for (int i=1; i < 19; i++){
                               board[i][0] = "border";
                          }
                          
                          for (int i=1; i<19; i++){
                               board[i][19] = "border";
                          }
                          for (int i=1; i<19; i++){
                               board[0][i] = "border";
                          }
                          for (int i=1; i<19; i++){
                               board[19][i] = "border";
                          }
                          System.out.println("Created board borders.");
                          
                          board[0][0] = "borderC";
                          board[0][19] = "borderC";
                          board[19][0] = "borderC";
                          board[19][19] = "borderC";
                          System.out.println("Created border corners.");
                     }
                     
                     public void fillBoard() {
                          for (int i=0; i<20; i++){
                               for (int w=0; w<20; w++){
                                    board[w][i] = "background";
                               }
                          }
                     }
                     
                     public String[][] getBoard(){
                          return board;
                     }
                     
                     public void setGameView(GameView gv) {
                          gameView = gv;
                     }
                     
                     public Snake getSnake() {
                          return snake;
                     }
                     
                     public void addSnakeSegment(int n) {
                          for (int i=0; i<n; i++){
                               snake.addSegment();
                          }
                     }
                     
                     public ArrayList<Segment> getSegments() {
                          return segments;
                     }
                     
                     public Food getFood(){
                          return currentFoodItem;
                     }
                     
                     public void makeFood(){
                          currentFoodItem = new Food();
                          board[currentFoodItem.getX()][currentFoodItem.getY()] = "food";
                          System.out.println("Food item is located a X: " + currentFoodItem.getX() + " Y: " + currentFoodItem.getY());
                     }
                     
                     public void setScore(int score){
                          this.score = score;
                          gameView.scoreLabel.updateScore(score);
                     }
                     
                     public int getScore(){
                          return score;
                     }
                     
                     //this method creates the snake, initial piece of food
                     public void startGame(){
                          
                          snake.addFirstSegment();
                          board[9][9] = "segment";
                     }
                     
                     public void changeWorld() {
                          ArrayList<Segment> snakeSegs = snake.getSnake();
                          for (Segment s : snakeSegs){
                               s.move();
                          }
                          gameView.somethingChanged();
                          
                     }
                     
                     public void moveSnakeUp(){
                          for (Segment s : snake.getSnake()){
                               //get velocities
                               double xv = s.getXVel();
                               double yv = s.getYVel();
                               int v = (int)Math.sqrt(xv*xv+yv*yv);
                               s.setXVel(0);
                               s.setYVel(-v);
                          }
                          System.out.println("Moved snake up.");
                          gameView.somethingChanged();
                     }
                     
                     public void moveSnakeDown(){
                for(Segment s : snake.getSnake()){
                double xv = s.getXVel();
                double yv = s.getYVel();
                int v = (int)Math.sqrt(xv*xv+yv*yv);
                // Set velocities
                s.setXVel(0);
                s.setYVel(v);

                }
                // tell view to update
                gameView.somethingChanged();
                }
                     
                     public void moveSnakeRight(){
                     for(Segment s : snake.getSnake()){
                     double xv = s.getXVel();
                     double yv = s.getYVel();
                     int v = (int)Math.sqrt(xv*xv+yv*yv);
                     // Set velocities
                     s.setXVel(v);
                     s.setYVel(0);

                     }
                     // tell view to update
                     gameView.somethingChanged();
                     }
                     
                     public void moveSnakeLeft(){
                for(Segment s : snake.getSnake()){
                // Calc velocity
                double xv = s.getXVel();
                double yv = s.getYVel();
                int v = (int)Math.sqrt(xv*xv+yv*yv);
                // Set velocities
                s.setXVel(-v);
                s.setYVel(0);
                }
                // tell view to update
                gameView.somethingChanged();
                }
                     
                     
                }
                And then the code for my Snake class:
                import java.util.ArrayList;

                public class Snake {
                     
                     private GameModel model;
                     private GameView gameView;
                     private ArrayList<Segment> snake;
                     
                     public Snake(GameModel model, GameView view){
                          this.model = model;
                          this.gameView = view;
                          snake = new ArrayList<Segment>();
                     }
                     
                     public void addSegment(){
                          int length = snake.size();
                          if (length == 0){
                               snake.add(new Segment(model, gameView));
                          }
                          else {
                               Segment previous = snake.get(length-1);
                               int xVel = previous.getXVel();
                               int yVel = previous.getYVel();
                               if (xVel != 0){     //Check to see if segment is moving on x axis
                                    if (xVel > 0){     //If segment is going right
                                         snake.add(new Segment(model, gameView, previous.getgridx()-1, previous.getgridy()));
                                    }
                                    else {     //If segment is moving left
                                         snake.add(new Segment(model, gameView, previous.getgridx()+1, previous.getgridy()));
                                    }
                               }
                               else { //If segment is moving vertically
                                    if (yVel > 0){      //if segment is moving down
                                         snake.add(new Segment(model, gameView, previous.getgridx(), previous.getgridy()-1));
                                    }
                                    else { //If segment is moving up
                                         snake.add(new Segment(model, gameView, previous.getgridx(), previous.getgridy()+1));
                                    }
                               }
                               
                          }
                               
                     }
                     
                     public void addFirstSegment(){
                          snake.add(new Segment(model, gameView, 9, 9));
                     }
                     
                     public int snakeLength(){
                          return snake.size();
                     }
                     
                     public ArrayList<Segment> getSnake(){
                          return snake;
                     }
                     
                     

                }
                I figured putting absolutely everything in my project up here may be a little much, but if there is anything else I need to provide let me know. I looked over my code before I responded here, and I'm still overlooking something because I couldn't find anything...