简体   繁体   中英

ConcurrentModificationException with Iterators

I've been coding a program and I've faced several issues that I was able to address properly. However, my program is throwing a ConcurrentModificationException and I'm not sure what I can do.

I'm coding with NetBeans 8.0.2 to create a Java desktop application (as required by my professor). The aim of the program is to manage a hotel. So, it has some parts like "Customers", "Staff" and "Booking" (the one giving me problems).

On each part, I have a JTable that uses a DefaultTableModel . In every part, I'm using files on the hard drive to make the changes persistent. I've coded new customer/staff classes. Now, I'm trying to code booking and unbooking methods. Everything has gone pretty well until I got to the "unbooking" part.

After the table and model I have an ArrayList . In this particular part, I have three of them:

  • one for the whole table
  • one containing only the free rooms
  • one only with the already booked rooms.

The booking part was fine, I'm able to modify the table, the file and the ArrayList without any errors, and my program actually does what it should. But I'm unable to get the unbooking part to work. It should basically be the reverse of booking.

I will post a small part of my code, but if you need to know anything else or need some more parts of my code I would gladly share it.

My code:

public class GestionInstalaciones extends javax.swing.JFrame {
    private final String ruta = System.getProperties().getProperty("user.dir");
    private final File archivo = new File (ruta+"\\Instalaciones.txt");
    private final DefaultTableModel modelo = new DefaultTableModel();
    private final ArrayList contenidoInstalaciones;
    private final ArrayList contenidoInstalacionesOcupadas;
    private final ArrayList contenidoInstalacionesLibres;
    public GestionInstalaciones() {
       initComponents ();
       contenidoInstalaciones = new ArrayList();
       contenidoInstalacionesOcupadas = new ArrayList();
       contenidoInstalacionesLibres = new ArrayList();
       //Añadimos las columnas a la tabla.
       modelo.addColumn ("Tipo");
       modelo.addColumn ("Nombre Instalacion");
       modelo.addColumn ("NIF del Ocupante");
       cargarTabla();
}

private void cargarTabla(){
    this.contenidoInstalaciones.clear();
    FileReader fr = null;
    BufferedReader br;
    String tipo;
    String nombre;
    String NIFocupante;
    String[] partes;
    String linea;

    try{
        fr = new FileReader(archivo);
        br = new BufferedReader(fr);

        while ((linea=br.readLine())!=null) {
            //Adding info to general ArrayList
            this.contenidoInstalaciones.add(linea);
            //Splitting line into 3 components.
            partes = linea.split(",",3);
            tipo = partes[0];
            nombre = partes[1];
            NIFocupante = partes[2];

            //Skipping header.
            if ( tipo.equals( "Tipo" )) { continue; }

            //Añadimos la fila al modelo.
            modelo.addRow(partes);
        }
        TablaInstalaciones.setModel(modelo);
    }
    //Capturamos excepciones y cerramos fichero.
    catch(IOException e) {}
    finally { try { if ( null != fr ) { fr.close(); } } catch (IOException e2){ } }
}//end cargarTabla()

private void botonLiberarInstalacionActionPerformed(java.awt.event.ActionEvent evt) {                                                        
    Object linea;
    int contador=0;
    String aux; 
    String tiposATrabajar = "";
    String[] tiposAInsertar;
    Iterator instalacionesOcupadas;

    //Cleaning of already booked ArrayList.
    //this.contenidoInstalacionesOcupadas.clear();

    instalacionesOcupadas = contenidoInstalacionesOcupadas.iterator();
    this.comboTipoALiberar.removeAllItems();
    this.comboTipoALiberar.addItem("Seleccione");

    //Reading the general Table.
    for (int z = 0; z < TablaInstalaciones.getRowCount() ; z++) {
        //The booking parameter is on the 3rd place.
        if(!TablaInstalaciones.getValueAt(z,2).equals("")){
            //Putting the line into the ArrayList for booked rooms..
            linea = TablaInstalaciones.getValueAt(z,0) + "," + TablaInstalaciones.getValueAt(z,1) + "," + TablaInstalaciones.getValueAt(z,2);
            this.contenidoInstalacionesOcupadas.add(linea);
            contador++;
        }
    }

    **//Reading the booked ArrayList to put the right values on the combobox related. 
      //===> THIS LINE IS GIVING THE ERROR !!!
    while(instalacionesOcupadas.hasNext()) {** 
        aux = instalacionesOcupadas.next().toString().split(",",3)[0];
        //Checking to add only 1 kind of each room type.
        if(!tiposATrabajar.contains(aux)); {
            if (tiposATrabajar.equals("")) { tiposATrabajar=aux; }
            else { tiposATrabajar = tiposATrabajar + "," + aux; }
        }
    }      
    //
    tiposAInsertar = tiposATrabajar.split(",");
    //Adding the type into the combobox.
    for (String elemento: tiposAInsertar){ this.comboTipoALiberar.addItem(elemento.replace(",","")); }

}   

ConcurrentModificationException s happen when you make changes to a chain of elements (list) while you're actively looping through said chain.

I've encountered it often enough and always solve it by reverse looping through the list, that way you loop backwards and you can change or delete elements if you want without messing up the chain (list) you're looping over.

I'd provide you with code, but I find it very hard to read yours, so this'll have to do for now.

Hope this helps and good luck!

If the contents of the Collection you are iterating through have been changed since the last time you have used an iterator, you will get an exception if you try to use or reuse it. Create a new one - as a general rule, don't reuse an iterator .

You are:

  1. Creating an iterator
  2. Modifying the list
  3. Using the iterator after the list has been modified ← Error!

You should modify the list before creating the iterator.

Also, you should try to minimize the scope of local variables .

As opposed to:

Iterator<String> someIterator = strings.iterator();
while (someIterator.hasNext()) {
    doSomething();
}

You should probably do:

for (Iterator<String> iter = strings.iterator(); iter.hasNext();) {
    doSomething();
}

Of course, if you (as you said) do not need to modify the list, use a for-each loop:

for (String s : strings) {
    doSomething();
}

Some unrelated points:

  • Why are you writing things like extends java.awt.JFrame ? Import it and use JFrame instead.
  • Declare and initialize your variables when you need them. If you had initialized the Iterator only in front of your for loop you wouldn't have had this problem.
  • Use generics ! Non-generic Collection s will only err at run-time, while generic ones will give compile errors instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM