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

Time:12-25

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].

CodePudding user response:

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);
}

CodePudding user response:

You're getting an incorrect result during multiplication because when the last element is being processed, the list looks like this [6, 2, 8, 2] (the element at index 1 has been changed to 2). Therefore, indexOf() return 1, not 3 (as you probabely expected).

In cases like this when you need to replace each element in the list, you can use Java 8 method List.replaceAll() which is far more convenient since you don't need to dial with indices:

numbers.replaceAll(number -> number * 2);

System.out.println(numbers);

Output:

[6, 2, 8, 4]
  • Related