collections.shuffle 是 java 中专为 list 设计的原地随机打乱工具,需传入可变 arraylist,避免 arrays.aslist() 等不可变列表;抽样取前 n 个即可实现公平随机,测试用固定种子,生产用默认随机源。

Collections.shuffle 是 Java 中最直接、最可靠的集合随机化工具,它不造轮子、不拼接字符串、不依赖排序陷阱,专为 List 设计,一次调用就完成原地打乱。
必须用可变的 ArrayList
shuffle 只接受支持 set() 和 get() 的 List 实现。常见错误是传入 Arrays.asList() 返回的列表——它底层是固定大小的内部类,调用 shuffle 会抛 UnsupportedOperationException。
- 正确做法:用 new ArrayList(Arrays.asList(...)) 包一层再 shuffle
- 错误写法:Collections.shuffle(Arrays.asList("A", "B", "C")) —— 编译通过但运行报错
- Set 或 Map 需先转 List:new ArrayList(mySet),再 shuffle
抽奖与随机采样就这么取
不需要循环抽、不用去重校验、不担心重复中奖——打乱后取前 N 个就是公平随机结果。
- 中奖名单:shuffledList.subList(0, Math.min(n, shuffledList.size()))
- 题库抽 5 道题:shuffle 后取前 5 个,天然无序且无偏
- 避免“抽完删一个再重 shuffle”:那会破坏 Fisher-Yates 的等概率保证
测试时要能复现,生产时要真随机
默认 shuffle 用系统时间作种子,毫秒级密集调用可能撞上相同序列;而单元测试需要每次跑出一样结果。
- 测试写法:Collections.shuffle(list, new Random(123L))
- 生产保持默认:Collections.shuffle(list) 即可
- Java 17+ 的 Random 已默认使用 LXM 算法,均匀性优于旧版,无需额外替换
别踩这些坑
看似简单的方法,几个边界情况容易引发空指针、并发异常或性能抖动。
- null 检查不能少:调用前 if (list == null) throw … 或用 Objects.requireNonNull
- 多线程共用同一 list?加锁,或用 Collections.synchronizedList 包装后再操作
- LinkedList shuffle 性能差:O(n²) 随机访问,大数据量务必先转 ArrayList
- 空列表或单元素列表:shuffle 不报错也不动作,这是设计行为,不是 bug
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











