Update ArrayList using another ArrayList in java

2k Views Asked by At

I've come across a lot of information on ArrayLists and how to manipulate them but nothing seems to be answering my issue.

I want to check if an element in an arraylist is not alive, and if so remove it but add another 2 to the list. Usually quite easy except that I need to then add the changes to another arraylist that contains all the elements in the first arraylist as well as elements from other external arraylists.

I thought Id be able to do this using a temp arraylist as shown below:

import java.util.ArrayList;

public class main {

    public static ArrayList<String> changedArr = new ArrayList(){ {add("M1"); add("alive"); add("M3");} };
    public static ArrayList<String> tempArr = new ArrayList();
    public static ArrayList<String> totalArr = new ArrayList(){ {add("M1"); add("alive"); add("M3"); add("L4"); add("S5");} };

    public static void main(String[] args) {

        System.out.println("changedArray = "+changedArr);
        System.out.println("tempArray = "+tempArr);
        System.out.println("totalArray = "+totalArr);

        for(Object a : changedArr){
            if(a !="alive") {
                tempArr.clear();
                changedArr.remove(a);
                totalArr.remove(a);
                tempArr.add("S6");
                tempArr.add("S7");
                changedArr.addAll(tempArr);
                totalArr.addAll(tempArr);
            }
        }
        System.out.println("\nchangedArray = "+changedArr);
        System.out.println("tempArray = "+tempArr);
        System.out.println("totalArray = "+totalArr);
    }
}

Where this code should return:

changedArray = [M1, alive, M3]
tempArray = []
totalArray = [M1, alive, M3, L4, S5]

changedArray = [alive, S6, S7]
tempArray = [S6, S7]
totalArray = [alive, L4, S5, S6, S7]

It's instead returning:

Exception in thread "main" java.util.ConcurrentModificationException
changedArray = [M1, M2, M3]
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
tempArray = []
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
totalArray = [M1, M2, M3, L4, S5]
    at main.main(main.java:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Process finished with exit code 1

So my question is, what am I doing wrong to cause these errors? Is this method possible? If not, I don't see why, could you explain? And how could I get around it?

If you've made it this far, thanks for taking the time to read my ramblings! :D

5

There are 5 best solutions below

0
Max Weinzierl On BEST ANSWER

You are modifying your ArrayList changedArr while iterating over it using an enhanced for loop. This causes a ConcurrentModificationException to be thrown because enhanced for loops produce iterators for the looping to occur, and iterators assume that the list will not me modified during the iterator's lifetime. If you modify a list while an iterator is iterating over it then you will get a ConcurrentModificationException.

A solution would be to have an original list and a copy and only modify the copy. You should never modify a list while you are iterating over it.

0
bichito On
for (Object a : changedArr)

creates an implicit iterator on the list. If you modify the list then the next iteration will fail.

Try a normal for loop using indices. This should help you around the exception

0
Screwb On

Change your code like this:

List<Object> copy = changedArr.stream().collect(Collectors.toList());

    for (Object a : copy) {
        if (a != "alive") {
            tempArr.clear();
            changedArr.remove(a);
            totalArr.remove(a);
            tempArr.add("S6");
            tempArr.add("S7");
            changedArr.addAll(tempArr);
            totalArr.addAll(tempArr);
        }
    }
0
Gooz On

A ConcurrentModificationException is thrown because you're modifying changedArr while iterating over it. The iterator notices these changes and throws an exception. A very clear and easy way you could solve this, is by using a ListIterator:

ListIterator iterator = changedArr.listIterator();
while (iterator.hasNext()) {
    Object a = iterator.next();
    if (a != "alive") {
        iterator.remove(); // removes 'a' from changedArr
        iterator.add("S6"); // adds "S6" to changedArr
        iterator.add("S7");
        // etc.
    }
}
0
Eishknaar On

Thanks a lot for your advice @Max Weinzierl, worked brilliantly! I added an 'addedArr' array to use as a middle-man.

For anyone who might have a similar issue, here's the re-jigged code:

import java.util.ArrayList;

public class main {

    public static ArrayList<String> changedArr = new ArrayList(){ {add("M1"); add("alive"); add("M3");} };
    public static ArrayList<String> addedArr = new ArrayList();//----- New ArrayList 'addedArr' used for adding the new elements
    public static ArrayList<String> tempArr = new ArrayList();
    public static ArrayList<String> totalArr = new ArrayList(){ {add("M1"); add("alive"); add("M3"); add("L4"); add("S5");} };

    public static void main(String[] args) {
        tempArr.addAll(changedArr);//--------------------------------- Duplicated changedArr
        System.out.println("addedArray = "+addedArr);
        System.out.println("tempArray = "+tempArr);
        System.out.println("changedArray = "+changedArr);
        System.out.println("totalArray = "+totalArr+"\n");
        int counter = 0;//-------------------------------------------- Counter to increment the added elements

        for(Object a : changedArr){
            addedArr.clear();//--------------------------------------- Make sure 'addedArr' is cleared at start of each loop
            if(a !="alive") {
                tempArr.remove(a);
                totalArr.remove(a);
                addedArr.add("S"+(6+counter));
                counter++;
                addedArr.add("S"+(6+counter));
                counter++;
                tempArr.addAll(addedArr);//--------------------------- Adds new elements to tempArr to be added to changedArr
                totalArr.addAll(addedArr);//-------------------------- Adds new elements to totalArr
            }
            System.out.println("addedArray = "+addedArr);
        }
        changedArr.clear();//----------------------------------------- Clear changedArr to make sure that anything removed in the loop is removed
        changedArr.addAll(tempArr);//--------------------------------- Add all changes from tempArr to changedArr
        System.out.println("\ntempArray = "+tempArr);
        System.out.println("changedArray = "+changedArr);
        System.out.println("totalArray = "+totalArr);
    }
}