传递arraylist的副本以避免并发修改异常

时间:2016-08-11 10:40:00

标签: java concurrentmodification

我在java下面抛出ConcurrentModificationException下面的java代码是java代码

下面的

是要声明的列表

List<BrokerInvoiceLineItem> brokerInvoiceLineItems= new ArrayList<BrokerInvoiceLineItem>();
            brokerInvoiceLineItems=brokerInvoice.getLineItems();
下面的

是抛出并发修改异常的代码

if (brokerInvoiceLineItems == null) {
    brokerInvoiceLineItems = brokerInvoiceHome.findLineitemsByInvoiceId(brokerInvoice.getId());
}
for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems) {
    if (fetchNewAndOldCFandAmend(brokerInvoiceLineItem)) {
        if (!isAnyValid)
            isAnyValid = true;
    }
}

现在的问题是,如果brokerInvoiceLineItems不为null,那么对于第一次迭代,它进入循环内部,并且将值设置为名为isAnyValid的变量的true,但是第一次迭代结束后,第二次迭代结束时,它将转到行for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems){然后它不会进入它引发并发修改例程的下一行

所以这意味着它必须在迭代时修改brokerInvoiceLineItems的大小。这可能发生在fetchNewAndOldCFandAmend中,因此我考虑制作brokerInvoiceLineItems的副本并改为修改副本。所以请告知我如何将副本传递给fetchNewAndOldCFandAmend(brokerInvoiceLineItem)

另请注意如何使用copyonwriteArray列表来避免此类错误

3 个答案:

答案 0 :(得分:1)

我认为当您删除brokerInvoiceLineItems的某些项目时会出现此异常。

要避免此异常,请使用迭代器

Iterator<BrokerInvoiceLineItem> iterator = brokerInvoiceLineItems.iterator();
while(iterator.hasNext()) {
  BrokerInvoiceLineItem brokerInvoiceLineItem = iterator.next();
    // your code
}

而不是

for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems) {

所以你的代码是:

Iterator<BrokerInvoiceLineItem> iterator = brokerInvoiceLineItems.iterator();
while(iterator.hasNext()) {
  BrokerInvoiceLineItem brokerInvoiceLineItem = iterator.next();
  if (fetchNewAndOldCFandAmend(brokerInvoiceLineItem)) {
    if (!isAnyValid)
      isAnyValid = true;
  }
}

答案 1 :(得分:0)

您应该创建一个新的ArrayList,并将之前ArrayList对象的所有元素添加到其中。

ArrayList<BrokerInvoiceLineItem> otherList = new ArrayList<BrokerInvoiceLineItem>();
otherList.addAll(brokerInvoiceLineItems);

注意:如果您更改for语句,例如:

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

你不会得到ConcurrentModificationException。

更新:示例代码:

if (brokerInvoiceLineItems == null) {
    brokerInvoiceLineItems = brokerInvoiceHome.findLineitemsByInvoiceId(brokerInvoice.getId());
}

ArrayList<BrokerInvoiceLineItem> otherList = new ArrayList<BrokerInvoiceLineItem>();
otherList.addAll(brokerInvoiceLineItems);

for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems) {
    if (fetchNewAndOldCFandAmend(otherList)) {
        if (!isAnyValid)
            isAnyValid = true;
    }
}

答案 2 :(得分:0)

我假设您正在修改方法brokerInvoiceLineItems中的fetchNewAndOldCFandAmend。您可以使用CopyOnWriteArrayList 而不是ArrayList。这允许您迭代列表,同时更新它。这需要一些成本,因为每次添加内容时它都会创建一个新数组。示例代码如下所示:

    // Member field declaration
    List<BrokerInvoiceLineItem> brokerInvoiceLineItems;

    // Retrieve the list of objects
    List<BrokerInvoiceLineItem> items = brokerInvoice.getLineItems();
    if (items == null) {
        items = brokerInvoiceHome.findLineitemsByInvoiceId(brokerInvoice.getId());
    }

    // Initialize your member variable to be a 
    // CopyOnWriteArrayList with the above elements
    brokerInvoiceLineItems = new CopyOnWriteArrayList<>(items);

    // Iterate over the elements and possibly update the list from
    // the fetchNewAndOldCFandAmend method
    for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems) {
        if (fetchNewAndOldCFandAmend(brokerInvoiceLineItem)) {
            if (!isAnyValid)
                isAnyValid = true;
        }
    }

我的代码假设您有一个存储BrokerInvoiceLineItem列表的类,并且它在构造函数中进行了初始化。

通常,迭代列表并调用另一个更新它的方法是个坏主意。您可以使用迭代器遍历它并删除某些元素。您的fetchNewAndOldCFandAmend可能用于指示是否应从列表中删除当前项目并调用迭代器的删除方法。