collections.shuffle 是 java 中基于 fisher-yates 算法的公平随机乱序工具,需传入可修改 list,支持固定种子重现结果,原地操作非线程安全,推荐 arraylist 以保障 o(n) 性能。

Collections.shuffle 是 Java 中最直接、最可靠的集合乱序工具,一行代码就能完成公平随机打乱,无需手写循环或额外逻辑。它不是“伪随机”,而是基于 Fisher-Yates 算法严格保证每种排列等概率,适用于抽奖、题库抽题、菜单轮播等真实场景。
必须用可修改的 List,否则会报错
shuffle 只接受支持 set() 和 listIterator() 的 List 实现。常见陷阱包括:
- Arrays.asList("A", "B", "C") 返回固定大小列表,调用 shuffle 会抛 UnsupportedOperationException
-
int[] 或 String[] 数组不能直接传入,需先转为 List
或 List - Collections.unmodifiableList() 同样不可用
安全写法:始终用 new ArrayList(original) 包一层再 shuffle。
抽奖和随机采样:打乱一次,取前 N 个即可
不需要 while 循环去重、不依赖重复抽取、也不用担心顺序偏差。逻辑极简且天然公平:
- 把所有参与者加入 ArrayList
- 调用 Collections.shuffle(list)
- 用 list.subList(0, Math.min(N, list.size())) 获取中奖名单
即使 N 大于总人数,Math.min 也能自动兜底,避免 IndexOutOfBoundsException。
让结果可重现:传入带种子的 Random
默认 shuffle 使用系统时间作为种子,每次结果不同。但测试、审计或游戏存档需要确定性输出:
- 用 new Random(123L) 创建固定种子实例
- 调用 Collections.shuffle(list, fixedRandom)
- 相同输入 + 相同 seed → 每次 shuffle 结果完全一致
生产环境仍用无参版本;高安全要求场景可换用 SecureRandom。
注意线程安全与性能适配
shuffle 是原地操作,非线程安全:
- 多线程同时 shuffle 同一列表,需加锁或改用线程局部副本
- 空列表、单元素列表、含 null 元素的列表均可安全调用,无副作用
- 对 ArrayList,shuffle 是 O(n) 时间 + O(1) 空间;对 LinkedList,JDK 会先转数组再回写,大数据量时性能明显下降
高频乱序场景建议统一使用 ArrayList,避免隐性开销。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











