Error removing item from ArrayList

1

I'm "joking" with the canvas (android) and I'm having trouble removing element from an ArrayList.

The app works like this: The user clicks on the screen, a ball appears that goes up but I want to remove only the balls that have exceeded the limit of y <= -50 . When I go to remove it it generates this error:

09-08 23:28:12.617: E/AndroidRuntime(6719):  FATAL EXCEPTION: Thread-2330
09-08 23:28:12.617: E/AndroidRuntime(6719):  java.lang.IndexOutOfBoundsException: Invalid index 1, size is 1
09-08 23:28:12.617: E/AndroidRuntime(6719):  at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
09-08 23:28:12.617: E/AndroidRuntime(6719):  at java.util.ArrayList.get(ArrayList.java:304)
09-08 23:28:12.617: E/AndroidRuntime(6719):  at com.dotjogoqualquer.JogoView.update(JogoView.java:50)
09-08 23:28:12.617: E/AndroidRuntime(6719):  at com.dotjogoqualquer.JogoView.run(JogoView.java:40)
09-08 23:28:12.617: E/AndroidRuntime(6719):  at java.lang.Thread.run(Thread.java:856)

Code

public void update() {
                if (obj.size() >= 1){
                        for(int x = 0; x < obj.size(); x++) {
                                obj.get(x).y -= 15;
                                if (obj.get(x).y < -50) {
                                        obj.remove(x); //Erro ocorre aqui
                                }
                        }
                }
                postInvalidate();
        }

Links to the complete code link (Line 48)

    
asked by anonymous 09.09.2015 / 22:17

2 answers

2

The error happens because you are removing the list items from within a for, this is because when the for was "mounted" by the VM the list had an X size, you removed some items , so when calling list.get (x) ex is greater than the number of items in the list an exception will be thrown.

In a FOR, its first two parts (variable declaration and stop condition) are called only once.

Suppose your list has 10 items, so the obj.size() call will return 10, as the stop condition is x < 10 , the loop will run regardless of whether items have been removed or added to the list. Let's imagine that the list has 10 items:

 for(int x = 0; x < obj.size(); x++) { // Aqui foi definido que o loop vai até X == 9

      // Se um item for removido, vai dar erro AQUI 
      // na ultima iteração do loop, pois o tamanho da lista será 8 e x será 9
      obj.get(x).y -= 15; 

      if (obj.get(x).y < -50) { //Se nenhum item for removido não vai dar erro

          obj.remove(x); 
      }
 }

In addition there are more elegant ways of doing the same thing, if you are using Java 7 you can use the Guava to apply to your logic. Using Guava would look like this:

     List<TipoDeDados> listaTransformada = Lists.transform(lista, new Function<TipoDeDados, TipoDeDados>() {

        @Override
        public TipoDeDados apply(TipoDeDados input) {
            input.y -= 15;
            return input;
        }
    });

    Iterables.removeIf(listaTransformada, new Predicate<TipoDeDados>() {

        @Override
        public boolean apply(TipoDeDados input) {
            return input.y < -50;
        }
    });

The good thing about using the Function and Predicate classes is that you can give a descriptive name for the implementations, which makes the algorithm easier to understand.

If you are using version 8 of Java, it is simpler still, just use the methods of the List interface itself, thus:

    lista.forEach( tipoDeDado -> tipoDeDado.y -= 15);

    lista.removeIf( tipoDeDado -> tipoDeDado.y < -50 );
    
16.10.2015 / 04:23
0

Is there more than one thread moving the list at the same time? Try to surround all of the code snippets that deal with this list with

synchronized (obj) {     ... }

The entire body of the question method must be protected in this way. By the way, check if the size () > = 1 is unnecessary because the loop does nothing if the list has no element.

    
12.09.2015 / 06:20