iCodeLikeImDrunk
iCodeLikeImDrunk

Reputation: 17806

Running into java.util.ConcurrentModificationException while iterating list

I'm trying to split a list of records into sublists of records. I successfully split the list into sublists, I wanted to see the contents of the sublists, but somehow I keep running into this ConcurrentModificationException.

My split method:

/**
     * @param list - list of results
     * @param size - how many sublists
     * @return ret - returns a list containing the sublists
     * */
    public static <T> List<List<T>> split(List<T> list, int size) throws NullPointerException, IllegalArgumentException {
        if (list == null) {
            throw new NullPointerException("The list parameter is null.");
        }
        if (size <= 0) {
            throw new IllegalArgumentException("The size parameter must be more than 0.");
        }

        int recordsPerSubList = list.size() / size; // how many records per sublist
        List<List<T>> sublists = new ArrayList<List<T>>(size); // init capacity of sublists

        // add the records to each sublist
        for (int i=0; i<size; i++) {
            sublists.add(i, list.subList(i * recordsPerSubList, (i + 1) * recordsPerSubList));
        }

        // for the remainder records, just add them to the last sublist
        int mod = list.size() % recordsPerSubList;
        if (mod > 0) {
            int remainderIndex = list.size() - mod;
            sublists.get(size - 1).addAll(list.subList(remainderIndex, list.size()));
        }

        return sublists;
    }

I call it here:

List<List<QuoteSearchInfo>> ret = Util.split(quoteSearchInfoList, 5);

            int fileCounter = 0;
            for (List<QuoteSearchInfo> sublist : ret) {
                fileCounter++;

                String sublistJson = new Gson().toJson(sublist);
                filename = JSON_FILE_NAME + fileCounter + JSON_FILE_END;
                saveToFile(filename, sublistJson);
                AWSManager.getInstance().uploadQuoteSearchJson(filename);
            }

^ Here I am trying to split the list into sublists so I can upload them to S3.

and the stack trace:

java.util.ConcurrentModificationException 
at java.util.SubList.checkForComodification(AbstractList.java:752) 
at java.util.SubList.listIterator(AbstractList.java:682) 
at java.util.AbstractList.listIterator(AbstractList.java:284) 
at java.util.SubList.iterator(AbstractList.java:678) 
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:95) 
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:60) 
at com.google.gson.Gson.toJson(Gson.java:546)
at com.google.gson.Gson.toJson(Gson.java:525) 
at com.google.gson.Gson.toJson(Gson.java:480) 
at com.google.gson.Gson.toJson(Gson.java:460) 
at com.crover.QuoteSearchRover.execute(QuoteSearchRover.java:41) 
at com.crover.CroverMain.execute(CroverMain.java:85) 
at com.crover.CroverMain.main(CroverMain.java:35)

Upvotes: 2

Views: 1733

Answers (1)

Louis Wasserman
Louis Wasserman

Reputation: 198023

sublists.get(size - 1).addAll(list.subList(remainderIndex, list.size()));

sublists.get(size - 1) is a live view of a subrange of the list, so when you add elements to it, you're adding elements to the original list as well, at the same time that you're trying to get elements out from list.subList. In general, you can't modify a list while you're iterating over it.

The simplest solution is not to add the elements to sublists.get(size - 1), but just to update it:

sublists.set(size - 1, 
   list.subList(remainderIndex - recordsPerSublist, list.size()));

Upvotes: 6

Related Questions