java - 带有迭代器的 ConcurrentModificationException

标签 java arraylist concurrency concurrentmodification

我一直在编写一个程序,遇到了几个我能够正确解决的问题。但是,我的程序抛出 ConcurrentModificationException 并且我不确定我能做什么。

我正在使用 NetBeans 8.0.2 进行编码以创建 Java 桌面应用程序(按照我的教授的要求)。 该计划的目的是管理一家酒店。因此,它有一些部分,例如“客户”、“员工”和“预订”(给我带来问题的部分)。

在每个部分,我都有一个使用 DefaultTableModelJTable。在每个部分中,我都使用硬盘驱动器上的文件来使更改持久化。我已经编写了新的客户/员工类(class)。现在,我正在尝试编写预订和取消预订方法的代码。一切都很顺利,直到我到达“取消预订”部分。

在表格和模型之后,我有一个ArrayList。在这个特定的部分中,我有三个:

  • 整个表格一个
  • 仅包含空闲房间
  • 仅限已预订的房间。

预订部分很好,我可以修改表、文件和ArrayList,没有任何错误,而且我的程序实际上做了它应该做的事情。但我无法让取消预订部分发挥作用。它基本上应该与预订相反。

我将发布我的代码的一小部分,但如果您需要了解其他任何内容或需要我的代码的更多部分,我很乐意分享。

我的代码:

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(",","")); }

}   

最佳答案

如果您正在迭代的 Collection 的内容自上次使用迭代器以来已发生更改,则在尝试使用或重用它时将会出现异常。创建一个新的 - 作为一般规则,don't reuse an iterator .

你是:

  1. 创建迭代器
  2. 修改列表
  3. 列表修改后使用迭代器←错误!

您应该在创建迭代器之前修改列表。

此外,您应该尝试minimize the scope of local variables .

相对于:

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

你可能应该这样做:

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

当然,如果您(正如您所说)不需要修改列表,请使用 for-each 循环:

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

一些不相关的点:

  • 你为什么要写extends java.awt.JFrame之类的东西? Import它并使用 JFrame 代替。
  • 在需要时声明并初始化变量。如果您仅在 for 循环前面初始化了Iterator,则不会出现此问题。
  • 使用generics !非泛型Collection只会在运行时出错,而泛型则会给出编译错误。

关于java - 带有迭代器的 ConcurrentModificationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41485145/

相关文章:

java - 将一个 Java 对象引用替换为另一个被认为是线程安全的对象引用,还是我忽略了潜在的同步性问题?

Java 内存可见性和 AtomicReference 的

java - 使用 S3 DeleteObject 仅删除文件,保持目录结构不变

java.net.ConnectException : Connection refused when SocketChannel. open 被调用

Java 内部接口(interface)作为返回类型

java - 比较两个 ArrayList

java - 这个项目结构有效吗?

c# - 如何检查ArrayList中对象的类型

java - 如何实现List<T>到T[]转换的通用方法?

java - 无界无等待?