0.導言
本文主要是介紹在Java中生成隨機數的不同選擇和方式。實際應用中根據自己的需要選擇。
1.Java API
在Java本身自帶的API中,為我們提供了幾種方式來獲得隨機數。我們來看下。
1.1. java.lang.Math
Math類的random方法將返回一個範圍為0.0(包括0.0)到1.0(不包括1.0)的雙精度值。看看該如何使用它來獲得一個在給定的範圍(最小和最大值間)內定義的隨機數:
<code>int randomWithMathRandom = (int) ((Math.random() * (max - min)) + min);/<code>
這行代碼的意思為為,我們用兩個整數,表示結果的隨機數的取值範圍在min和max之間。直接在JShell中簡要演示這個實現,我這裡參考如下(每次的結果可能都不同):
1.2. java.util.Random
在Java 1.7之前,最流行的生成隨機數的方法是使用nextInt。有兩種途徑使用使用這個方法,即帶參數和不帶參數。無參數調用以近似相等的概率返回任何int值。所以很有可能得到負數,參考代碼如下:
<code>Random random = new Random();/<code>
<code>int randomWithNextInt = random.nextInt();/<code>
我在本機JShell中運行結果如下:
如果使用綁定參數的netxInt方法(參數對返回值進行範圍約定了),我們將得到一個範圍內的數字,示例如下:
<code>int aVal = random(ival) ;/<code>
注意:這類需要主要,ival值必須是大於0,返回值在0和ival之間,但不包含ival;若參數小於等於0,則會報錯: java.lang.IllegalArgumentException.。
演示:那麼要想得到一個在min和max之間的整數,我在JShell中演示結果如下:
Java 8引入了新的ints方法,此方法返回java.util.stream.IntStream。IntStream,LongStream,DoubleStream等用於操作流中的數據,同時提供了相應的靜態方法來初始化它們自己。讓我們看看如何使用它們。
沒有參數的ints方法返回一個無限的int流,其代碼示例如下:
<code>IntStream unlimitedIntStream = random.ints();/<code>
也可以傳入一個參數限制流大小,示例如下:
<code>IntStream limitedIntStream = random.ints(streamSize);/<code>
當然,我們可以設置最大和最小值來生成帶範圍的int流,示例如下:
<code>IntStream limitedIntStreamWithinARange = random.ints(streamSize, min, max);/<code>
具體用戶可以查看Java API參考。
1.3. java.util.concurrent.ThreadLocalRandom
Java 1.7之後,為我們帶來了一種通過ThreadLocalRandom類來生成隨機數的更高效的新方法。這個類與隨機類有三個重要區別:
- ü 不需要顯式地初始化ThreadLocalRandom的新實例。這有助於避免創建大量無用實例和浪費垃圾收集器時間的錯誤;
- ü 不能為ThreadLocalRandom設置種子,這會導致一個實際的問題。如果我們需要設置種子,那麼我們應該避免使用這種產生隨機數的方式;
- ü Random (隨機)類在多線程環境中表現不佳。
下面看看其工作方式:
<code>int randomWithThreadLocalRandomInARange = ThreadLocalRandom.current().nextInt(min, max);/<code>
使用Java 8或更高版本,我們就有了新的可能性。
首先,nextInt方法有兩種變體:
<code>int randomWithThreadLocalRandom = ThreadLocalRandom.current().nextInt();/<code>
<code>int randomWithThreadLocalRandomFromZero = ThreadLocalRandom.current().nextInt(max);/<code>
其次,更重要的是,我們可以使用ints方法:
<code>IntStream streamWithThreadLocalRandom = ThreadLocalRandom.current().ints();/<code>
1.4. java.util.SplittableRandom
Java 8還給我們帶來了一個非常快的生成器——SplittableRandom類。
正如我們在JavaDoc中看到的,這是一個用於並行計算的生成器。重要的是要知道實例不是線程安全的。所以,我們在使用這個類時必須小心。
還提供了nextInt和ints方法。使用nextInt,我們可以直接使用兩個參數設置最高最低範圍來調用:
<code>SplittableRandom splittableRandom = new SplittableRandom();/<code>
<code>int randomWithSplittableRandom = splittableRandom.nextInt(min, max);/<code>
這種方法可以檢查max參數是否大於min,否則會得到一個IllegalArgumentException。但是,它不能檢查我們是用正數還是負數。所以,參數都可以是任何負的。此外,我們還提供了一參和零參的調用。它們的工作方式和我們之前描述的一樣。
也有ints方法。這意味著我們可以很容易地獲得一個int流。必須清楚,使用中可以選擇一個有限的或無限的流。對於一個有限的流,我們可以設置最高最低的數字生成範圍約束:
<code>IntStream limitedIntStreamWithinARangeWithSplittableRandom = splittableRandom.ints(streamSize, min, max);/<code>
1. .5. java.security.SecureRandom
如果我們有安全敏感的應用程序,或說安全要求高的,推薦考慮使用SecureRandom。這是一個加密的強生成器。默認構造的實例不使用加密隨機種子。所以,我們應該:
- ü 設置種子-但種子將是不可預測的;
- ü 設置java.util.secureRandomSeed系統屬性為true;
這個類繼承自java.util.Random。因此,我們可以使用上面看到的所有方法。例如,如果我們需要獲取任何int值,那麼可調用沒有參數的nextInt:
<code>SecureRandom secureRandom = new SecureRandom();/<code>
<code>int randomWithSecureRandom = secureRandom.nextInt();/<code>
另一方面,如果我們需要設置範圍,我們可以調用帶參數的方法:
<code>int randomWithSecureRandomWithinARange = secureRandom.nextInt(max - min) + min;/<code>
必須當心:如果參數不大於0,這種使用方法會拋出IllegalArgumentException。
2.第三方API
正如我們所看到的,Java為我們提供了許多生成隨機數的類和方法。然而,還有第三方提供的API服務於此目的。我們來看看其中的一些。
2.1. org.apache.commons.math3.random.RandomDataGenerator
在Apache commons項目的commons數學庫中有很多生成器。最簡單,也可能最有用的就是RandomDataGenerator。它使用Well19937c(https://en.wikipedia.org/wiki/Well_equidistributed_long-period_linear)算法進行隨機生成。但是,我們可以提供我們的算法實現。
讓我們看看如何使用它。首先,我們必須添加依賴:
<dependency>
<groupid>org.apache.commons/<groupid>
<artifactid>commons-math3/<artifactid>
<version>3.6.1/<version>
可以在Maven Central上找到commons-math3的最新版本。
導入項目後,就可以開始使用它們工作了,示例如下:
<code>RandomDataGenerator randomDataGenerator = new RandomDataGenerator();/<code>
<code>int randomWithRandomDataGenerator = randomDataGenerator.nextInt(min, max);/<code>
2.2. it.unimi.dsi.util.XoRoShiRo128PlusRandom
這是最快的隨機數生成器實現之一。它是由米蘭大學信息科學系開發的。
該庫也可以在Maven中央存儲庫中使用。因此,讓引用時可以如下添加依賴:
<dependency>
<groupid>it.unimi.dsi/<groupid>
<artifactid>dsiutils/<artifactid>
<version>2.6.0/<version>
這個生成器繼承自java.util.Random。但是,如果我們看一下JavaDoc,就會發現只有一種方法可以使用它——nextInt方法。最重要的是,此方法僅可用於零參數和單參數調用。其他任何調用都將直接使用java.util.Random隨機方法。
例如,如想要得到一個範圍內的隨機數,你可以這樣寫:
<code>XoRoShiRo128PlusRandom xoroRandom = new XoRoShiRo128PlusRandom();/<code>
<code>int randomWithXoRoShiRo128PlusRandom = xoroRandom.nextInt(max - min) + min;/<code>
3.最後
通過本文,我們知道了有幾種實現隨機數生成的方法。然而,沒有最好的方法。因此,我們應該選擇最適合我們需要的。
你還知道有哪些有趣的隨機數生成類,分享一下吧.
閱讀更多 牛旦教育IT課堂 的文章