Search code examples
javaloopsnestedconcurrentmodification

ConcurrentModificationException when removing item in nested loops


This is my code, and I obtained a ConcurrentModificationException when I removed an element. I do not understand why itrGrupo1 is affected by removing an element in itrGrupo2.

The exception occurs at: Instancia inst1=(Instancia) itrGrupo1.next() when the second while is finished.

for (int i=0; i<lstPrimeraAgrupacion.size();i++){

  List grupo1=new ArrayList();
  List grupo2=new ArrayList();
  grupo1=(List) lstPrimeraAgrupacion.get(i);         
  grupo2=(List) lstPrimeraAgrupacion.get(i);         

  Iterator itrGrupo1 = grupo1.iterator();
  while(itrGrupo1.hasNext()) {

      List nuevoGrupo=new ArrayList();

      Instancia inst1=(Instancia) itrGrupo1.next();         
      int edad1=Integer.valueOf(inst1.getEdadH());
      int carnet1=Integer.valueOf(inst1.getCarnetH());
      int antigCli1=Integer.valueOf(inst1.getAntigCli());

      Iterator itrGrupo2 = grupo2.iterator();
      while(itrGrupo2.hasNext()) {

          Instancia inst2=(Instancia) itrGrupo2.next();
          int edad2=Integer.valueOf(inst2.getEdadH());
          int carnet2=Integer.valueOf(inst2.getCarnetH());
          int antigCli2=Integer.valueOf(inst2.getAntigCli());

          if(cond){
              nuevoGrupo.add(inst2);
              itrGrupo2.remove();
          }

      }

      // Put in the final list
      if (!nuevoGrupo.isEmpty()){
          lstNuevosGrupos.add(nuevoGrupo);
      }

  }

}

Solution

  • The problem exists due to the following lines:

    List grupo1=new ArrayList();
    List grupo2=new ArrayList();
    grupo1=(List) lstPrimeraAgrupacion.get(i);         
    grupo2=(List) lstPrimeraAgrupacion.get(i);
    

    The first two lines of this create two new ArrayLists, but the lines following them make grupo1 and grupo2 point to the same, existing list. I feel that this is desired for grupo2, since you are modifying it, and it looks like the desired effect of this code is to modify lstPrimeraAgrupacion's ith sub-list. (I'm assuming that lstPrimeraAgrupacion is a List<List<Instancia>>, or a list of sub-lists of Instancia objects.)

    What the body of your code does is look through grupo1 for any elements that match a condition, and then removes them from grupo2. However, if these two variables reference the same List<Instancia> object, then modifying grupo2 will also change what your iterator over grupo1 has access to, potentially leaving it in a broken state (which is why you got the exception).

    Now, there are far better approaches to resolving the problem of iterating over a list and removing elements, but the way that you've designed your code, the lowest-impact solution would be to simply duplicate the elements into a new List, and use that as a snapshot of the old list, while you remove elements as needed from the actual list. To do this, you can change the above code to the following:

    List grupo1=new ArrayList();
    List grupo2=null;
    grupo1.addAll((List) lstPrimeraAgrupacion.get(i)); // Copies the list into our new ArrayList pointed to by grupo1
    grupo2=(List) lstPrimeraAgrupacion.get(i); // Makes grupo2 point to the existing List so we can modify it directly.