Home > Mobile >  Iterate through list and add to list without incurring ConcurrentModificationException - Java
Iterate through list and add to list without incurring ConcurrentModificationException - Java

Time:03-04

Apologies, this has been done to death but I am really struggling to implement a solution to this problem and I am quite new to Java.

I need to be able to call a method which basically allows a Person object to be added to a list. The method needs to check if that person is already in the list. It needs to perform the check by first name - I know in reality this seems daft but it is something that I need to be able to do in this particular scenario.

The list then needs to be available to the class so a print list of names method can be called later.

The main problem I have encountered whilst trying to implement a solution is a 'ConcurrentModificationException' which is understandable given I have been trying to update the list whilst in the middle of a for each loop.

So, I have come up with the following solution which prevents the 'ConcurrentModificationException' but my solution doesn't work properly and seems overcomplicated - see following code snippet of method:

public void addPerson(Person aPerson) {
    // tempPersons list for temporarily storing Person objects
    tempPersons = new ArrayList<>();

    // if persons list is initially empty, add aPerson object to it
    if (persons.isEmpty()) {
        persons.add(aPerson);
    }
    // if persons list is not initially empty
    if (!persons.isEmpty()) {
        // loop through persons list
        for (Person anotherPerson : persons) {
            // if persons list anotherPerson first name is the same as the aPerson first name, print message
            if (anotherPerson.getFirstName().equals(aPerson.getFirstName())) {
                System.out.println("The Person "   aPerson.getFirstName()  
                        " is already entered in the list");
            }
            // otherwise add the aPerson object to the tempPersons list
            else {
                tempPersons.add(aPerson);
            }
        }
        // once out of loop, add the tempPersons list to the racers list
        persons.addAll(tempPersons);
        // create new tempPersons2 list based on a hashset of the persons list so there are no duplicates
        List<Person> tempPersons2 = new ArrayList<>(
                new HashSet<>(persons));
        // assign tempPersons2 list without duplicates to persons list
        persons = tempPersons2;
    }
}

So, if for example I call the above addPerson method 4 separate times with a mixture of unique and duplicate objects (aPerson param), the method correctly identifies that there is already an object with the same first name in there but the persons list always seems to end up with a duplicate object (first name) in there e.g. if I have the following objects:

Person1 FirstName = Bob

Person2 FirstName = Jan

Person3 FirsName = Bob

Person4 FirstName = Ann

Then I make the following method call 4 separate times:

addPerson(Person1);

addPerson(Person2);

addPerson(Person3);

addPerson(Person4);

When I call a print method, I get the following output:

The Person Bob is already entered in the list

Jan

Ann

Bob

Bob

I would expect the following:

The Person Bob is already entered in the list

Jan

Ann

Bob

Apologies for all the waffle and what is probably a really simple solution to most of you but I have been stuck on this for a couple of days. Would appreciate it if anyone could provide a simple solution based on the example I have provided?

Similar article can be found here but I am still struggling.

Adding elements to a collection during iteration

CodePudding user response:

Without changing your code too much:

  public void addPerson(Person person) {
    // The guard is more or less a premature optimization and should be removed.
    if (persons.isEmpty()) {
      persons.add(person);
      return;
    }

    for (Person anotherPerson : persons) {
      if (anotherPerson.getFirstName().equals(person.getFirstName())) {
        System.out.println("The Person "   person.getFirstName()  
            " is already entered in the list");
        return;
      }
    }
    persons.add(person);
  }

This would exit the method when a match is found, if there are no matches the person is simply added after the loop. Note the return in the first check.

Optimizations of this code could be using a Map or Set to speed up the contains check; also just using anyMatch on persons would lead to a more elegant solution.

The duplicates are caused by your for loop and it's else condition. If Bob and Jan is in your collection and you add a second Bob then Jan won't be equal to Bob and your else path is executed adding a duplicate to your final persons List.

CodePudding user response:

You can use Set instead of list which will satisfy your need and implement the comparator or comparable interface for person comparison

  • Related