Java ArrayList.set()在forEach循环中乘法操作的异常行为疑问
问题分析:ArrayList forEach中使用indexOf导致的元素修改异常
问题重现
初始化数组
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()); // 输出:[3, 1, 4, 2] } }
加法操作(结果符合预期)
numbers.forEach(number -> { numbers.set(numbers.indexOf(number), number + 10); }); System.out.println(numbers.toString()); // 输出:[13, 11, 14, 12]
乘法操作(结果异常)
numbers.forEach(number -> { numbers.set(numbers.indexOf(number), number * 2); }); System.out.println(numbers.toString()); // 实际输出:[6, 4, 8, 2],预期输出:[6, 2, 8, 4]
问题根源
问题出在numbers.indexOf(number)的逻辑上:
indexOf()的作用是返回数组中第一个与目标元素相等的索引,并非当前遍历到的元素的索引。- 乘法操作的执行步骤拆解:
- 遍历第一个元素
3:indexOf(3)找到索引0,设置为3*2=6,数组变为[6,1,4,2] - 遍历第二个元素
1:indexOf(1)找到索引1,设置为1*2=2,数组变为[6,2,4,2] - 遍历第三个元素
4:indexOf(4)找到索引2,设置为4*2=8,数组变为[6,2,8,2] - 遍历第四个元素
2:此时数组中第一个2位于索引1,indexOf(2)返回1,于是把索引1的元素修改为2*2=4,最终数组变成[6,4,8,2]
- 遍历第一个元素
加法操作未出现异常,是因为每个元素加10后都是唯一值,indexOf()总能匹配到当前元素对应的正确索引,不会出现“找错位置”的情况。
解决方案
要避免这类问题,需要直接基于索引遍历,或使用不依赖元素值定位的修改方式:
方案1:普通for循环按索引遍历
for (int i = 0; i < numbers.size(); i++) { numbers.set(i, numbers.get(i) * 2); } System.out.println(numbers.toString()); // 输出:[6,2,8,4]
方案2:使用ListIterator(支持遍历中安全修改)
ListIterator<Integer> iterator = numbers.listIterator(); while (iterator.hasNext()) { iterator.set(iterator.next() * 2); } System.out.println(numbers.toString()); // 输出:[6,2,8,4]
方案3:使用ArrayList的replaceAll方法(最简洁)
numbers.replaceAll(number -> number * 2); System.out.println(numbers.toString()); // 输出:[6,2,8,4]
内容的提问来源于stack exchange,提问作者Sean
相关产品推荐
相关产品推荐

