Search code examples
javaarraysrecursionarraylistconcurrentmodification

concurrentmodification exception -- setting an array element


I read in JAVAdocs that concurrent modification exception comes when you structurally modify a list while iterating through it.In my case I am not changing the size of array but,just replacing some indices in the array. Tried out many things but this doesnt seem to work.

Providing a snippet below.(The code is a recursive function to solve n-queens problem)

    public ArrayList<ArrayList<String>> solve(int a, String[] arr,int beg,
ArrayList<ArrayList<String>> result) {      
    for( int i=beg;i< a*a ;i++){
        String s = arr[i];
        if(s.equals(".")){
            //fill Q and look for valid combs
           arr[i] = "Q";
           if(i== (a*a)-1){
                 String[] t = (String[])(arr.clone());
                 result.add(new ArrayList<String>(Arrays.asList(t)));
           }else{
               ArrayList<Integer> filled = fillX(arr,i,a,"x");//this function fills "X" in queen's path and returns the filled indices

               ArrayList<ArrayList<String>> tmp = solve(a,arr,i+1,result);
               if(!tmp.isEmpty()){
                    for(ArrayList<String> t :tmp){
                        result.add((ArrayList<String>)t.clone());
                     }
               }
                for(int x = 0;x< a*a;x++){                      
                    if(filled.contains(x)){
                        arr[x] = ".";//the exception goes away on removing this line
                    }                         
                }                 
           }
           arr[i] =".";
        }
    }
        return result;  
}

Stacktrace --

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at Solution.solve(Solution.java:29)
at Solution.solveNQueens(Solution.java:7)
at Main.main(Main.java:323)

Solution

  • I believe you hit a typical Concurrent Modification scenario.

    ArrayList<ArrayList<String>> tmp = solve(a, arr, i + 1, result);
    for (ArrayList<String> t : tmp) { // <-- iterating through the result of a recursive call.
        result.add((ArrayList<String>)t.clone());
    }
    ...
    return result; // <-- while the recursive call returns the `result` argument.
    

    It is basically doing something like:

    for (ArrayList<String> t : result) {
        result.add((ArrayList<String>)t.clone());
    }
    

    IMHO, you either can make resolve a void method, and add results directly to the passed in result argument; or you can remove the result parameter and make each recursive call create a local List and return it.