Search code examples
javaloopsexceptionconcurrentmodification

Cannot figure out why it throws ConcurrentModificationException


I've got the ConcurrentModificationException and do not know why. I know that trying to iterate through a list using for loops and deleting elements inside the loop block is bad idea and can throw such exception, but I have no idea how to fix it in my case.

 private static final List<Integer> originalList = new ArrayList<>();

    public static void main(String[] args) {

        for (int i = 0; i < 10; i++) {
            originalList.add(i);
        }


        final int MAX_GROUP_SIZE = 5;
        int partitionSize = 4;

        List<List<Integer>> partitions = new LinkedList<>();

        for (int i = 0; i < originalList.size(); i += partitionSize) {
            partitions.add(originalList.subList(i,
                    Math.min(i + partitionSize, originalList.size())));
        }

        int lastGroupSize = partitions.get(partitions.size() - 1).size();

        if (lastGroupSize < partitionSize && partitions.size() > lastGroupSize){
            List<Integer> lastGroup = partitions.remove(partitions.size() - 1);
            for (int i = 0; i < lastGroupSize; i++) {
                partitions.get(i).add(lastGroup.get(i));
            }
        }
        System.out.println("GROUPS: " + partitions.size());
        printGroups(new LinkedList<>(partitions));
    }

Solution

  • The problem is that your calls to subList() don't create new lists. As the javadoc says it:

    Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.

    The javadoc also says:

    The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list.

    When you call partitions.get(i).add(...), you're structurally modifying originalList, causing the error.

    I don't believe you intended that, so to fix the problem, you just need to make sure your sub-lists are independent of the original list, i.e. copies, which is easy to do:

    new ArrayList<>(originalList.subList(...))
    

    Using the ArrayList(Collection) constructor will create a copy of the sub-list.

    So, change this statement:

    partitions.add(originalList.subList(i,
            Math.min(i + partitionSize, originalList.size())));
    

    to this:

    partitions.add(new ArrayList<>(originalList.subList(i,
            Math.min(i + partitionSize, originalList.size()))));