Search code examples
javaarraylistforeachindexof

Unexpected behavior of Java ArrayList.set() method with multiplication in forEach loop


Setting initial array values (no issue):

import java.util.ArrayList;
public class arraylists {

    public static void main (String[] args) {
        ArrayList<Integer> numbers = new ArrayList<Integer>();
        numbers.add(3);
        numbers.add(1);
        numbers.add(4);
        numbers.add(2);
        System.out.println(numbers.toString());
    }
}

Console output: [3, 1, 4, 2]

Trying forEach addition (no issue):

numbers.forEach(number -> {
    numbers.set(numbers.indexOf(number), number + 10);
});
System.out.println(numbers.toString());

Console output: [13, 11, 14, 12]

Trying forEach multiplication:

numbers.forEach(number -> {
    numbers.set(numbers.indexOf(number), number * 2);
});
System.out.println(numbers.toString());

Console output: [6, 4, 8, 2]

My question is, why does the array after the multiplication loop have value 4 at index 1 and value 2 at index 3? Shouldn't they be 1 * 2 = 2 and 2 * 2 = 4, respectively?

I tried the above code and was expecting after the forEach multiplication to have an array with values [6, 2, 8, 4]. Instead I got [6, 4, 8, 2].


Solution

  • indexOf returns the index of the first occurrence of a value. Let's walk through the loop and see what's going on.

    1. We start with [3, 1, 4, 2]
    2. The first element is 3. Its index is 0, so we get [6, 1, 4, 2]
    3. The second element is 1. Its index is 1, so we get [6, 2, 4, 2]
    4. The third element is 4. Its index is 2, so we get [6, 2, 8, 2]
    5. The fourth element is 2. Its first index is 1, so we get [6, 4, 8, 2]

    Not only is this wrong (as you've seen), it also means that for each iteration you need to search the entire list (with indexOf) for a value that you already should have known where it is.

    Using a good old for loop would be better suited here:

    for (int i = 0; i < numbers.size(); ++i) {
        numbers.set(i, numbers.get(i) * 2);
    }