Collections.fill仅适用于已初始化且大小固定的List,如ArrayList或Arrays.asList返回的列表;它不扩容、不新建元素,仅替换已有位置的引用,对空集合无效。

用 Collections.fill 填充集合前,先确认它能不能用
Collections.fill 只能作用于**已存在且大小固定的 List**,比如 ArrayList 或 Arrays.asList 返回的列表。它不会扩容、不会新建元素,只是把已有位置上的引用全部替换成指定对象。
常见错误是拿它去“填充空集合”:new ArrayList() 是空的,Collections.fill(list, "x") 什么也不会做——没报错,但 list 还是空的。
- ✅ 正确用法:
ArrayListlist = new ArrayList(Collections.nCopies(1000, null)); Collections.fill(list, "default"); - ❌ 错误用法:
ArrayListlist = new ArrayList(); Collections.fill(list, "x"); // list 仍为空 - ⚠️ 注意:填的是引用,如果填的是可变对象(如
new StringBuilder()),所有位置都指向同一个实例
循环 add 和 Collections.fill 的性能差异主要在初始化阶段
两者根本不是同一类操作:循环 add 是“边扩容边写”,Collections.fill 是“写进已分配好的槽位”。性能对比必须控制变量——尤其是初始容量。
- 如果
ArrayList没预设容量,10 万次add会触发约 17 次数组扩容(每次复制老数组),实测慢 2–3 倍 - 如果提前
new ArrayList(size),再循环add,和Collections.fill性能几乎一致(JDK 17+,HotSpot 优化后) -
Collections.fill底层是Arrays.fill,走的是连续内存写入,在大尺寸时有缓存友好优势
简单验证:ArrayList
真正影响选择的不是性能,而是语义和安全性
你要的到底是“创建一个含 N 个默认值的列表”,还是“把现有列表所有元素覆盖成某值”?这决定了 API 选型。
- 初始化新列表 → 优先用
Collections.nCopies(n, value)(返回不可变列表)或Arrays.asList(new T[n])配合fill - 重置已有列表内容 →
Collections.fill更直接,且避免了clear() + add的额外扩容风险 - 要填的是不同对象(如 100 个独立
new Date())→ 只能循环add或流式构造,fill完全不适用
别为了省几纳秒去硬套 fill;语义错了,后期排查 NullPointerException 或共享状态 bug 才真花时间。
Collections.fill 在泛型和 null 场景下的隐性限制
它不校验类型兼容性,也不处理 null 元素的特殊逻辑,出问题往往在运行时才暴露。
- 对
ArrayList调用fill(list, "abc")会编译通过(泛型擦除),但运行时抛ClassCastException - 填
null没问题,但若 list 是ArrayList,填> null后后续get().isPresent()就 NPE - 对
LinkedList用fill—— 能用,但性能差很多,因为set(i, x)是 O(n) 遍历,不如ArrayList的 O(1)
实际项目里,看到 fill 出现在 LinkedList 上,基本可以认定是没想清楚数据结构选型。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











