Java 8 中的 Random 類

魔王不造反發表於2018-03-30

在Java8中 java.util.Random 類的一個非常明顯的變化就是新增了返回隨機數流(random Stream of numbers)的一些方法。

下面的程式碼是建立一個無窮盡的double型別的數字流,這些數字在0(包括0)和1(不包含1)之間。

Random random = new Random();
DoubleStream doubleStream = random.doubles(); 
複製程式碼

下面的程式碼是建立一個無窮盡的int型別的數字流,這些數字在0(包括0)和100(不包括100)之間。

Random random = new Random();
IntStream intStream = random.ints(0, 100); 
複製程式碼

那麼這些無窮盡的數字流用來做什麼呢?接下來,我通過一些案例來分析。記住,這些無窮大的數字流只能通過某種方式被截斷(limited)。

示例1:建立10個隨機的整數流並列印出來:

intStream.limit(10).forEach(System.out::println);
複製程式碼

示例2:建立100個隨機整數:

List<Integer> randomBetween0And99 = intStream
                                       .limit(100)
                                       .boxed()
                                       .collect(Collectors.toList()); 
複製程式碼

對於高斯偽隨機數(gaussian pseudo-random values)來說,random.doubles()方法所建立的流不能等價於高斯偽隨機數,然而,如果用java8所提供的功能是非常容易實現的。

Random random = new Random();
DoubleStream gaussianStream = Stream.generate(random::nextGaussian).mapToDouble(e -> e); 
複製程式碼

這裡,我使用了Stream.generate api,並傳入Supplier 類的物件作為引數,這個物件是通過呼叫Random類中的方法 nextGaussian()建立另一個高斯偽隨機數。

接下來,我們來對double型別的偽隨機數流和double型別的高斯偽隨機數流做一個更加有意思的事情,那就是獲得兩個流的隨機數的分配情況。預期的結果是:double型別的偽隨機數是均勻的分配的,而double型別的高斯偽隨機數應該是正態分佈的。

通過下面的程式碼,我生成了一百萬個偽隨機數,這是通過java8提供的api實現的:

Random random = new Random();
DoubleStream doubleStream = random.doubles(-1.0, 1.0);
LinkedHashMap<Range, Integer> rangeCountMap = doubleStream.limit(1000000)
        .boxed()
        .map(Ranges::of)
        .collect(Ranges::emptyRangeCountMap, (m, e) -> m.put(e, m.get(e) + 1), Ranges::mergeRangeCountMaps);

rangeCountMap.forEach((k, v) -> System.out.println(k.from() + "\t" + v)); 
複製程式碼

程式碼的執行結果如下:

-1      49730
-0.9    49931
-0.8    50057
-0.7    50060
-0.6    49963
-0.5    50159
-0.4    49921
-0.3    49962
-0.2    50231
-0.1    49658
0       50177
0.1     49861
0.2     49947
0.3     50157
0.4     50414
0.5     50006
0.6     50038
0.7     49962
0.8     50071
0.9     49695 
複製程式碼

為了類比,我們再生成一百萬個高斯偽隨機數:

Random random = new Random();
DoubleStream gaussianStream = Stream.generate(random::nextGaussian).mapToDouble(e -> e);
LinkedHashMap<Range, Integer> gaussianRangeCountMap =
    gaussianStream
            .filter(e -> (e >= -1.0 && e < 1.0))
            .limit(1000000)
            .boxed()
            .map(Ranges::of)
            .collect(Ranges::emptyRangeCountMap, (m, e) -> m.put(e, m.get(e) + 1), Ranges::mergeRangeCountMaps);

gaussianRangeCountMap.forEach((k, v) -> System.out.println(k.from() + "\t" + v)); 
複製程式碼

上面程式碼輸出的結果恰恰與我們預期結果相吻合,即:double型別的偽隨機數是均勻的分配的,而double型別的高斯偽隨機數應該是正態分佈的。

用偽隨機數所得的結果:

Java 8 中的 Random 類

用高斯偽隨機數所得的結果:

Java 8 中的 Random 類

附:完整程式碼可點選這裡獲取


歡迎關注知乎專欄《跟上Java8》,分享優秀的Java8中文指南、教程,同時歡迎投稿高質量的文章。

原文連結: javacodegeeks
翻譯: ImportNew.com - 踏雁尋花
譯文連結: www.importnew.com/9672.html


相關文章