Java中生成不重復(fù)隨機(jī)數(shù)的四種方法舉例詳解
摘要:
在Java開(kāi)發(fā)中,生成不重復(fù)的隨機(jī)數(shù)是常見(jiàn)的需求,例如抽獎(jiǎng)、隨機(jī)抽樣等場(chǎng)景。本文提供四種高效實(shí)現(xiàn)方案,涵蓋不同范圍與數(shù)據(jù)量的場(chǎng)景,并附完整代碼示例。
一、需求場(chǎng)景分析
生成不重復(fù)隨機(jī)數(shù)的核心問(wèn)題是“如何避免重復(fù)”。根據(jù)不同的范圍與生成數(shù)量,我們需要選擇不同的策略:
-范圍小且需全覆蓋(如1~100):適合預(yù)生成后打亂順序。
-范圍大但數(shù)量少(如1~100000取10個(gè)):適合動(dòng)態(tài)生成并去重。
-中等范圍動(dòng)態(tài)生成(如1~1000取100個(gè)):適合逐步移除已選值。
二、具體實(shí)現(xiàn)方法
方法1:使用`Collections.shuffle`打亂順序
適用場(chǎng)景:固定范圍內(nèi)生成所有值的不重復(fù)序列(如洗牌算法)。
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ShuffleDemo { public static void main(String[] args) { int min = 1, max = 100; List<Integer> numbers = new ArrayList<>(); for (int i = min; i <= max; i++) { numbers.add(i); } Collections.shuffle(numbers); // 關(guān)鍵:隨機(jī)打亂順序 // 獲取前10個(gè)不重復(fù)值 numbers.stream().limit(10).forEach(System.out::println); } }
優(yōu)點(diǎn):時(shí)間復(fù)雜度O(n),效率極高。
缺點(diǎn):需預(yù)先生成所有值,內(nèi)存占用高。
方法2:通過(guò)`Set`去重
適用場(chǎng)景:從大范圍中生成少量隨機(jī)數(shù)(如從1~100000中取10個(gè))。
import java.util.HashSet; import java.util.Random; import java.util.Set; public class SetDemo { public static void main(String[] args) { int min = 1, max = 100_000, count = 10; Set<Integer> uniqueNumbers = new HashSet<>(); Random random = new Random(); while (uniqueNumbers.size() < count) { int num = random.nextInt(max - min + 1) + min; uniqueNumbers.add(num); // Set自動(dòng)去重 } uniqueNumbers.forEach(System.out::println); } }
優(yōu)點(diǎn):內(nèi)存占用低。
缺點(diǎn):生成數(shù)量接近范圍上限時(shí)性能驟降。
方法3:動(dòng)態(tài)移除已選值
適用場(chǎng)景:中等范圍動(dòng)態(tài)生成(如從1~1000中取500個(gè))。
import java.util.ArrayList; import java.util.List; import java.util.Random; public class PoolDemo { public static void main(String[] args) { int min = 1, max = 1000, count = 10; List<Integer> pool = new ArrayList<>(); for (int i = min; i <= max; i++) { pool.add(i); } Random random = new Random(); for (int i = 0; i < count; i++) { int index = random.nextInt(pool.size()); int num = pool.remove(index); // 移除已選值 System.out.println(num); } } }
優(yōu)點(diǎn):避免重復(fù)碰撞問(wèn)題。
缺點(diǎn):頻繁操作List可能導(dǎo)致性能下降。
方法4:Java 8 Stream API(簡(jiǎn)潔寫(xiě)法)
適用場(chǎng)景:快速生成少量不重復(fù)值。
import java.util.Random; import java.util.stream.IntStream; public class StreamDemo { public static void main(String[] args) { int min = 1, max = 100, count = 10; Random random = new Random(); IntStream.generate(() -> random.nextInt(max - min + 1) + min) .distinct() // 去重 .limit(count) // 限制數(shù)量 .forEach(System.out::println); } }
優(yōu)點(diǎn):代碼簡(jiǎn)潔,適合函數(shù)式編程。
缺點(diǎn):不適用于生成數(shù)量接近范圍上限的場(chǎng)景。
三、性能與注意事項(xiàng)
1. 范圍與數(shù)量的關(guān)系**:必須滿足 `count ≤ (max - min + 1)`,否則代碼會(huì)陷入死循環(huán)。
2. 線程安全:多線程環(huán)境下建議使用 `ThreadLocalRandom`。
3. 性能對(duì)比:
- 最優(yōu)場(chǎng)景:`Collections.shuffle` > 動(dòng)態(tài)移除 > Set > Stream
- 最差場(chǎng)景:(如生成999/1000個(gè)值):動(dòng)態(tài)移除 > `Collections.shuffle` > Set > Stream
四、總結(jié)
| 方法 | 適用場(chǎng)景 | 推薦指數(shù) |
| `Collections.shuffle` | 小范圍全覆蓋 | ???? |
| `Set`去重 | 大范圍取少量值 | ??? |
| 動(dòng)態(tài)移除 | 中等范圍動(dòng)態(tài)取值 | ???? |
| Stream API | 代碼簡(jiǎn)潔且數(shù)量遠(yuǎn)小于范圍 | ?? |
建議根據(jù)實(shí)際需求選擇最合適的方法,避免因算法選擇不當(dāng)導(dǎo)致性能問(wèn)題。
到此這篇關(guān)于Java中生成不重復(fù)隨機(jī)數(shù)的四種方法的文章就介紹到這了,更多相關(guān)Java生成不重復(fù)隨機(jī)數(shù)方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java實(shí)現(xiàn)生成n個(gè)不重復(fù)的隨機(jī)數(shù)
- Java案例實(shí)現(xiàn)不重復(fù)的隨機(jī)數(shù)
- JAVA 16位ID生成工具類含16位不重復(fù)的隨機(jī)數(shù)數(shù)字+大小寫(xiě)
- Java編程實(shí)現(xiàn)生成給定范圍內(nèi)不重復(fù)隨機(jī)數(shù)的方法小結(jié)
- JAVA生成八位不重復(fù)隨機(jī)數(shù)最快的方法總結(jié)(省時(shí)間省空間)
- Java編程實(shí)現(xiàn)從給定范圍內(nèi)隨機(jī)N個(gè)不重復(fù)數(shù)生成隨機(jī)數(shù)的方法小結(jié)
- Java ArrayList如何實(shí)現(xiàn)生成不重復(fù)隨機(jī)數(shù)
- Java生成N個(gè)不重復(fù)的隨機(jī)數(shù)的三種方法總結(jié)
相關(guān)文章
mybatis學(xué)習(xí)之路mysql批量新增數(shù)據(jù)的方法
這篇文章主要介紹了mybatis學(xué)習(xí)之路mysql批量新增數(shù)據(jù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02MyBatisPlus使用@TableField注解處理默認(rèn)填充時(shí)間的問(wèn)題
這篇文章主要介紹了MyBatisPlus使用@TableField注解處理默認(rèn)填充時(shí)間的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01springMVC之HandlerExceptionResolver使用
這篇文章主要介紹了springMVC之HandlerExceptionResolver使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Java中5種方式實(shí)現(xiàn)String反轉(zhuǎn)
下面小編就為大家?guī)?lái)一篇Java中5種方式實(shí)現(xiàn)String反轉(zhuǎn)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。2016-06-06Java實(shí)現(xiàn)批量操作Excel的示例詳解
在操作Excel的場(chǎng)景中,通常會(huì)有一些針對(duì)Excel的批量操作,以GcExcel為例,為大家詳細(xì)介紹一下Java是如何實(shí)現(xiàn)批量操作Excel的,需要的可以參考一下2023-07-07Java查詢時(shí)間段(startTime--endTime)間的數(shù)據(jù)方式
這篇文章主要介紹了Java查詢時(shí)間段(startTime--endTime)間的數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03SpringBoot瘦身打包部署的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot瘦身打包部署的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04淺談java7增強(qiáng)的try語(yǔ)句關(guān)閉資源
下面小編就為大家?guī)?lái)一篇淺談java7增強(qiáng)的try語(yǔ)句關(guān)閉資源。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06spring boot starter actuator(健康監(jiān)控)配置和使用教程
這篇文章主要介紹了spring-boot-starter-actuator(健康監(jiān)控)配置和使用教程,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06