'ConcurrentModificationException with map of lists

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        Scanner sc=new Scanner(br);
        int T=Integer.parseInt(sc.nextLine());
        Map<String, List<Integer>> scores=new HashMap<>(); 
        List<Integer> zeros= new ArrayList<>();
        for (int t=0; t<T; t++) {
            //Begin solving here
            String key=sc.next();
            int score = Integer.parseInt(sc.nextLine().trim());
            zeros.add(0);
            if (scores.containsKey(key)) {
                int curScore = scores.get(key).get(t-1);
                scores.get(key).add(curScore + score);
            } else {
                scores.put(key, zeros);
                scores.get(key).set(t, score);
            }

The code above is buggy in that it produces the wrong result; the "zeros" list is aliased everywhere (I think; I'm learning Java)

        if (scores.containsKey(key)) {
            int curScore = scores.get(key).get(t-1); //This line throws the exception; line 27 on my editor
            scores.get(key).add(curScore + score);
        } else {
            scores.put(key, zeros.subList(0, t+1)); //Here I fix the aliasing bug
            scores.get(key).set(t, score);
        }

Test input

2
mike 5
mike 2

Exception thrown


Exception in thread "main" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1415)
    at java.base/java.util.ArrayList$SubList.get(ArrayList.java:1150)
    at div2.A.main(A.java:27)


Solution 1:[1]

The problem is a misconception around this line:

    scores.put(key, zeros.subList(0, t+1)); //Here I fix the aliasing bug

You're not "fixing the aliasing bug". The method subList does not return a new list. As the documentation says, "The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa."

It then 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."

You're structurally modifying the list, since you add an element (zeros.add(0)) to the original list after creating the sublist.

You should create a new list instead:

    scores.put(key, new ArrayList<>(zeros.subList(0, t+1)));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 k314159