用set集合配合random类实现去重抽奖:利用set自动去重,random生成[min,max]内随机数并add(),成功则计数,直至达目标人数;适合中奖数远小于总数的场景。

用 Set 集合配合 Random 类实现去重抽奖,核心思路是:利用 Set 的自动去重特性存储已抽中的号码,用 Random 不断生成随机数直到获得一个未抽过的新号——适合中奖人数远小于总池子的场景(比如从 1000 人里抽 10 个)。
准备数据池与结果容器
先明确抽奖范围(如编号 1~100),并用 Set 存储已中奖 ID,确保不重复:
- 用
HashSet<integer></integer>或LinkedHashSet(若需保留抽取顺序)作为中奖结果集 - 不需要提前把所有人放进集合;只需知道最大值
max和最小值min,用Random.nextInt(max - min + 1) + min生成随机编号 - 避免用
List存所有候选人再 shuffle——内存浪费且不必要
循环抽取直到满足数量
设定目标中奖人数 count,用 while 循环持续生成随机数并尝试加入 Set:
- 每次调用
set.add(randomNum),它返回true表示新增成功(即未重复),false表示已存在 - 只在返回
true时才计数器++,直到达到目标人数 - 注意:如果
count接近总人数(如 100 人里抽 95 个),失败重试次数会明显上升,此时应改用“洗牌后取前 N”方案
封装成可复用的方法
写一个通用方法,支持自定义范围和数量:
<font size="2"><pre class="brush:php;toolbar:false;">public static Set<integer> drawWithoutReplacement(int min, int max, int count) {<br> if (count > max - min + 1) {<br> throw new IllegalArgumentException("要抽的数量超过可用总数");<br> }<br> Random random = new Random();<br> Set<integer> winners = new LinkedHashSet();<br> while (winners.size() int num = random.nextInt(max - min + 1) + min;<br> winners.add(num); // 自动跳过重复<br> }<br> return winners;<br>}</integer></integer>
调用示例:drawWithoutReplacement(1, 50, 5) 表示从 1~50 中随机抽 5 个不重复的号码。
注意事项与优化建议
实际使用时需关注边界和性能:
- 多线程环境建议用
ThreadLocalRandom.current()替代new Random(),更安全高效 - 若抽奖对象是复杂对象(如
User),可先用 ID 抽,再查库;或让对象实现hashCode/equals,直接存对象到 Set - 需要高并发或超大数据量时,可考虑布隆过滤器预判,但一般业务场景无需过度设计











