Neera
Neera

Reputation: 41

passing an copy of arraylist to avoid concurrent modification exception

I have below java piece of code that throws ConcurrentModificationException below is the java piece of code

below is the lists that are being declared

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

below is the the piece of code that is throwing concurrentmodification exception

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

now the issue is that if brokerInvoiceLineItems is not null then for the first iteration it goes inside the loop and the value is set true of variable named isAnyValid but as soon the first iteration is over then for the second iteration it goesagain to the line for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems){ and then it does not go the next line it throws concurrent modification exeption

so this means it must be modifying brokerInvoiceLineItems size while iterating through it. This is probably occurring in fetchNewAndOldCFandAmend so i am consider making a copy of brokerInvoiceLineItems and modifying the copy instead. so please advise how can i pass the copy to fetchNewAndOldCFandAmend(brokerInvoiceLineItem)

Also please advise how to use copyonwriteArray list also to avoid such error

Upvotes: 2

Views: 3342

Answers (3)

Yorchus
Yorchus

Reputation: 1

You should create a new ArrayList and add to it all the elements of your previous ArrayList object.

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

Note: if you change your for statement for another like:

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

You'll not get that ConcurrentModificationException.

Update: example code:

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

Upvotes: 0

Slimu
Slimu

Reputation: 2371

I'm assumming that you are modifying the brokerInvoiceLineItems in the method fetchNewAndOldCFandAmend. You can use a CopyOnWriteArrayList instead of the ArrayList. This allows you to iterate the list and at the same time update it. There is some cost to this since it creates a new array everytime you add something to it. A sample code would look like this:

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

My code assumes that you have a class which stores a list of BrokerInvoiceLineItem and it's initialization is made in the constructor.

Usually it's a bad idea to iterate over a list and call another method which updates it. You can use an iterator to traverse it and remove certain elements. Your fetchNewAndOldCFandAmend maybe can be used to indicate if the current item should be removed from the list and call the iterator's remove method.

Upvotes: 0

beeb
beeb

Reputation: 1615

I think you get this exception when you remove some items of brokerInvoiceLineItems.

To avoid this exception, use an iterator

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

instead of

for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems) {

so your code is:

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

Upvotes: 1

Related Questions