ArrayList causing an IndexOutOfBoundsException


#1

I’m making a basic “Life” game, where larger circles eat smaller ones, and I keep getting a seemingly random IndexOutOfBoundsException.
This is the section of code that causes the error:

  for (int i = beings.size() - 1; i >=0; i--) {
    if (i < beings.size() ) {
      beings.get(i).display();
      beings.get(i).move();
      for (int j = beings.size() - 1; j >=0; j--) {
        if (j < beings.size() ) {
          if (beings.get(i).inside(beings.get(j).x, beings.get(j).y, beings.get(j).s) && beings.get(i).s > beings.get(j).s ) {
            beings.get(i).r = (beings.get(i).r + beings.get(j).r)/2;
            beings.get(i).g = (beings.get(i).g + beings.get(j).g)/2;
            beings.get(i).b = (beings.get(i).b + beings.get(j).b)/2;
            beings.remove(j);
          }
        }
      };
      if (beings.get(i).x > width || beings.get(i).x < 0 || beings.get(i).y > height || beings.get(i).y < 0) {
       beings.remove(i);
      }
    }
  }

The highlighted line is the if (beings.get(i).inside(beings.get(j).x, beings.get(j).y, beings.get(j).s) && beings.get(i).s > beings.get(j).s ) {. I tried adding safeguards to the code and searching the internet, but I couldn’t find anything.

And in case it’s helpful, here’s the being.inside function:

  boolean inside(int x2, int y2, int s2) {
    int r2 = s2/2;
    return (x - x2) * (x - x2) + (y - y2) * (y - y2) <= r2 * r2;
  }

Thanks in advance.


#2

after a

.remove ()

should leave loops, like with

break;

and before other item access in same upper loop must recheck size()

      if (i < beings.size() ) {
        if (beings.get(i).x > width || beings.get(i).x < 0 || beings.get(i).y > height || beings.get(i).y < 0) {
          beings.remove(i); 
        }
      }

your posted code should be a shorted version but fully functional
so we can run it without 20 min making class and main structure again.


#3

To expand on this: looping backwards through an array in order to do safe removal is something that works for a single-pass. As soon as you have nested loops on the same list, it becomes possible for you to delete references in the inner loop that the outer loop will then try to reference. Breaking is one way around this, but then you are skipping some comparisons, which might cause other problems. Another thing you can do is add your hits to a delete list – or mark those objects as dead using a class property – and then remove them in a sweep / garbage phase after the comparison phase is over.