
本文介绍一种简洁、可靠且性能优良的方法:先构建候选数字列表,再通过随机洗牌(shuffle)从中选取前 10 个元素,彻底避免重复问题。
在 Java 中生成指定范围内无重复的随机整数,最常见误区是使用“随机生成 + 逐个比对”的方式(如原代码中的 do-while 循环),这种方式不仅逻辑复杂、易出错,还存在无限循环风险(尤其当剩余可选数极少时),且仅与前一项比较(list[i] == list[i-1])根本无法检测数组中已存在的其他重复值——这正是示例输出中出现多个 0 和 16 的根本原因。
✅ 推荐方案:Fisher–Yates 洗牌 + 截取(Shuffle & Slice)
该方法基于“均匀随机排列”原理,时间复杂度 O(n),逻辑清晰,100% 无重复,且天然支持任意范围和数量:
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Assignment2_Q2 {
public static void main(String[] args) {
int[] myList = generateUniqueRandoms(0, 20, 10); // [min, max] inclusive, count=10
Arrays.sort(myList);
System.out.println("The array in sorted order:\n" + Arrays.toString(myList));
}
// ✅ 核心方法:生成 [min, max] 内 count 个不重复随机整数
public static int[] generateUniqueRandoms(int min, int max, int count) {
if (count > (max - min + 1)) {
throw new IllegalArgumentException(
String.format("Cannot select %d unique numbers from range [%d, %d]",
count, min, max));
}
// 1. 构建完整候选列表:0, 1, 2, ..., 20 → 共 21 个数
List candidates = IntStream.rangeClosed(min, max)
.boxed()
.collect(Collectors.toList());
// 2. 随机打乱顺序(内部使用 Fisher-Yates 算法)
Collections.shuffle(candidates, new Random()); // 显式传入 Random 更利于测试
// 3. 取前 count 个,并转为 int[] 数组
return candidates.subList(0, count).stream()
.mapToInt(Integer::intValue)
.toArray();
}
} ? 关键说明与注意事项:
- IntStream.rangeClosed(min, max) 生成包含边界的整数流(0 到 20 共 21 个数),完美匹配题目要求;
- Collections.shuffle() 是线程安全、高效且均匀的实现,远优于手写去重逻辑;
- 显式传入 new Random() 可提升可重现性(如需固定种子,可用 new Random(42));
- 添加了参数校验:当请求数量超过可用总数时(如要 25 个不重复数但范围只有 21 个),立即抛出异常,避免静默失败;
- 若需兼容 Java 8 以下版本,可用传统 for 循环填充 ArrayList
替代 IntStream。
? 延伸建议:
若后续需频繁调用或处理更大规模数据,可进一步封装为泛型工具类;对于极端性能敏感场景(如每秒百万次调用),可考虑 ThreadLocalRandom + 原始数组 + Knuth 洗牌优化,但本例中标准库方案已足够健壮高效。
此方法从设计源头杜绝重复,代码简洁可读,是生产环境推荐的标准实践。










