传递数组列表的副本以避免并发修改异常



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

下面是要声明的列表

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

是抛出concurrentmodification异常

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

现在的问题是,如果brokerinvoiceineitems不为null那么对于第一次迭代,它将进入循环并且变量isAnyValid的值设置为true但是一旦第一次迭代结束那么对于第二次迭代,它将再次进入for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems){行然后它不会进入下一行它抛出并发修改异常

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

还请告知如何使用copyonwriteArray列表也避免这样的错误

我认为当你删除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;
  }
}

我假设您正在修改fetchNewAndOldCFandAmend方法中的brokerInvoiceLineItems。你可以使用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;
        }
    }

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

迭代一个列表并调用另一个方法来更新它通常不是一个好主意。可以使用迭代器遍历它并删除某些元素。你的fetchNewAndOldCFandAmend也许可以用来指示当前项是否应该从列表中删除,并调用迭代器的remove方法。

你应该创建一个新的数组列表,并将之前的数组列表对象的所有元素添加到其中。

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;
    }
}

最新更新