collections.copy要求dest长度≥src长度,否则抛indexoutofboundsexception;必须用collections.ncopies预创建定长arraylist,不可用arrays.aslist()或空arraylist。

Collections.copy 要求目标列表(dest)的长度必须大于等于源列表(src)的长度,否则在复制过程中访问超出范围的索引时会抛出 IndexOutOfBoundsException。这不是运行时偶然错误,而是设计契约的明确约束。规范初始化的关键,在于**提前确保目标列表具备足够容量且元素可被安全覆盖**。
明确 dest 列表必须是可修改、定长、已预填充的 ArrayList
Collections.copy 不扩容、不添加元素,它只按索引逐个调用 set(i, element)。因此:
- 目标列表不能是
Arrays.asList()返回的固定大小列表(底层是数组,set合法但add不行,而它本身也不需要 add)——但问题在于它长度不可变,若小于 src 就必然越界; - 目标列表不能是空的
new ArrayList(),因为其 size = 0,无法 set 任何索引; - 正确做法:用
new ArrayList(Collections.nCopies(src.size(), null))或更直接地new ArrayList(java.util.Collections.<string>fill(new ArrayList(src.size()), null))</string>——但其实最简洁的是:
new ArrayList(java.util.Collections.nCopies(src.size(), null))
推荐初始化模式:用 src.size() 预创建确定长度的 ArrayList
不要依赖“先 new 再 add”,也不要假设目标列表已有内容。标准写法如下:
List<string> src = Arrays.asList("a", "b", "c");
List<string> dest = new ArrayList(Collections.nCopies(src.size(), null));
Collections.copy(dest, src); // ✅ 安全</string></string>
说明:
-
Collections.nCopies(n, null)返回一个不可变的、长度为 n 的列表; - 用它构造
ArrayList,会把 n 个null加入新列表,size = n,内部数组长度 ≥ n; - 后续
Collections.copy对每个i ∈ [0, src.size())调用dest.set(i, src.get(i)),全部合法。
替代方案:用构造器直接传入 src,语义更清晰
如果只是想获得 src 的副本,完全不需要 Collections.copy:
-
new ArrayList(src)—— 最常用、最直观,底层调用addAll,自动处理扩容; -
src.stream().collect(Collectors.toList())—— 函数式风格,同样安全; - 只有当需复用已有 dest 列表(例如缓存对象、避免频繁创建)且明确控制内存布局时,才用
Collections.copy,此时必须严格初始化 dest。
调试与验证:复制前加断言比捕获异常更规范
在关键路径中,建议显式校验而非依赖异常处理:
if (dest.size() <p>这样能:</p>
- 在早期暴露逻辑错误(比如误用了未初始化的 dest);
- 提供明确错误上下文,便于定位问题源头;
- 符合 fail-fast 原则,避免越界异常掩盖真实意图。










