Menjana Nombor Rawak di Jawa

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan meneroka pelbagai cara menghasilkan nombor rawak di Java.

2. Menggunakan Java API

API Java memberi kami beberapa cara untuk mencapai tujuan kami. Mari lihat sebahagian daripadanya.

2.1. java.lang.Math

The rawak kaedah yang Math kelas akan kembali dua nilai dalam julat dari 0.0 (termasuk) kepada 1.0 (eksklusif). Mari kita lihat bagaimana kita menggunakannya untuk mendapatkan nombor rawak dalam julat tertentu yang ditentukan oleh min dan maksimum :

int randomWithMathRandom = (int) ((Math.random() * (max - min)) + min);

2.2. java.util.Rawak

Sebelum Java 1.7, kaedah paling popular untuk menghasilkan nombor rawak adalah menggunakan nextInt . Terdapat dua cara menggunakan kaedah ini, dengan dan tanpa parameter. Permintaan tanpa parameter mengembalikan sebarang nilai int dengan kebarangkalian yang hampir sama. Jadi, kemungkinan besar kita akan mendapat nombor negatif:

Random random = new Random(); int randomWithNextInt = random.nextInt();

Sekiranya kita menggunakan permintaan netxInt dengan parameter terikat , kita akan mendapat nombor dalam julat:

int randomWintNextIntWithinARange = random.nextInt(max - min) + min;

Ini akan memberi kita nombor antara 0 (inklusif) dan parameter (eksklusif). Jadi, parameter terikat mesti lebih besar daripada 0. Jika tidak, kita akan mendapat java.lang.IllegalArgumentException .

Java 8 memperkenalkan kaedah ints baru yang mengembalikan java.util.stream.IntStream. Mari lihat bagaimana menggunakannya.

The ints kaedah tanpa parameter mengembalikan aliran yang tidak terhad int nilai:

IntStream unlimitedIntStream = random.ints();

Kami juga dapat memasukkan satu parameter untuk membatasi ukuran aliran:

IntStream limitedIntStream = random.ints(streamSize);

Dan, tentu saja, kita dapat menetapkan maksimum dan minimum untuk julat yang dihasilkan:

IntStream limitedIntStreamWithinARange = random.ints(streamSize, min, max);

2.3. java.util.concurrent.ThreadLocalRandom

Keluaran Java 1.7 memberi kami kaedah baru dan lebih berkesan untuk menghasilkan nombor rawak melalui kelas ThreadLocalRandom . Yang satu ini mempunyai tiga perbezaan penting dari kelas Rawak :

  • Kami tidak perlu secara eksplisit memulakan contoh baru ThreadLocalRandom . Ini membantu kita untuk mengelakkan kesilapan membuat banyak kejadian tidak berguna dan membuang masa pengumpul sampah
  • Kami tidak dapat menentukan pilihan untuk ThreadLocalRandom , yang boleh menyebabkan masalah yang sebenarnya. Sekiranya kita perlu menetapkan benih, maka kita harus mengelakkan cara ini menghasilkan nombor rawak
  • Kelas rawak tidak berfungsi dengan baik di persekitaran berbilang tali

Sekarang, mari lihat bagaimana ia berfungsi:

int randomWithThreadLocalRandomInARange = ThreadLocalRandom.current().nextInt(min, max);

Dengan Java 8 atau lebih tinggi, kami mempunyai kemungkinan baru. Pertama, kami mempunyai dua variasi untuk kaedah nextInt :

int randomWithThreadLocalRandom = ThreadLocalRandom.current().nextInt(); int randomWithThreadLocalRandomFromZero = ThreadLocalRandom.current().nextInt(max);

Kedua, dan yang lebih penting, kita boleh menggunakan kaedah ints :

IntStream streamWithThreadLocalRandom = ThreadLocalRandom.current().ints();

2.4. java.util.SplittableRandom

Java 8 juga membawa kami penjana yang sangat pantas - kelas SplittableRandom .

Seperti yang dapat kita lihat di JavaDoc, ini adalah penjana untuk digunakan dalam pengiraan selari. Penting untuk mengetahui bahawa contohnya tidak selamat di dalam benang. Jadi, kita harus berhati-hati semasa menggunakan kelas ini.

Kami telah menyediakan kaedah nextInt dan ints . Dengan nextInt kita dapat mengatur secara langsung julat atas dan bawah menggunakan dua parameter permintaan:

SplittableRandom splittableRandom = new SplittableRandom(); int randomWithSplittableRandom = splittableRandom.nextInt(min, max);

Cara menggunakan ini memeriksa bahawa parameter maksimum lebih besar daripada min . Jika tidak, kami akan mendapat IllegalArgumentException . Namun, ia tidak memeriksa sama ada kita bekerja dengan nombor positif atau negatif. Jadi, mana-mana parameter boleh menjadi negatif. Kami juga menyediakan satu-satu dan satu sifar parameter-doa. Mereka bekerja dengan cara yang sama seperti yang telah kita jelaskan sebelumnya.

Kami juga mempunyai kaedah ints . Ini bermaksud bahawa kita dapat memperoleh aliran nilai int dengan mudah . Untuk menjelaskan, kita boleh memilih untuk mempunyai aliran terhad atau tidak terhad. Untuk aliran terhad, kita dapat menetapkan bahagian atas dan bawah untuk julat penjanaan nombor:

IntStream limitedIntStreamWithinARangeWithSplittableRandom = splittableRandom.ints(streamSize, min, max);

2.5. java.security.SecureRandom

Sekiranya kita mempunyai aplikasi yang sensitif terhadap keselamatan, kita harus mempertimbangkan untuk menggunakan SecureRandom . Ini adalah penjana yang kuat secara kriptografi. Contoh yang dibina secara lalai tidak menggunakan biji rawak secara kriptografi. Oleh itu, kita harus:

  • Tetapkan benih - akibatnya, benih tidak dapat diramalkan
  • Tetapkan sifat sistem java.util.secureRandomSeed menjadi benar

Kelas ini diwarisi dari java.util.Random . Oleh itu, kami telah menyediakan semua kaedah yang kami lihat di atas. Sebagai contoh, jika kita perlu mendapatkan salah satu nilai int , maka kita akan memanggil nextInt tanpa parameter:

SecureRandom secureRandom = new SecureRandom(); int randomWithSecureRandom = secureRandom.nextInt();

Sebaliknya, jika kita perlu menetapkan julat, kita dapat menyebutnya dengan parameter terikat :

int randomWithSecureRandomWithinARange = secureRandom.nextInt(max - min) + min;

We must remember that this way of using it throws IllegalArgumentException if the parameter is not bigger than zero.

3. Using Third-Party APIs

As we have seen, Java provides us with a lot of classes and methods for generating random numbers. However, there are also third-party APIs for this purpose.

We're going to take a look at some of them.

3.1. org.apache.commons.math3.random.RandomDataGenerator

There are a lot of generators in the commons mathematics library from the Apache Commons project. The easiest, and probably the most useful, is the RandomDataGenerator. It uses the Well19937c algorithm for the random generation. However, we can provide our algorithm implementation.

Let’s see how to use it. Firstly, we have to add dependency:

 org.apache.commons commons-math3 3.6.1 

The latest version of commons-math3 can be found on Maven Central.

Then we can start working with it:

RandomDataGenerator randomDataGenerator = new RandomDataGenerator(); int randomWithRandomDataGenerator = randomDataGenerator.nextInt(min, max);

3.2. it.unimi.dsi.util.XoRoShiRo128PlusRandom

Certainly, this is one of the fastest random number generator implementations. It has been developed at the Information Sciences Department of the Milan University.

The library is also available at Maven Central repositories. So, let's add the dependency:

 it.unimi.dsi dsiutils 2.6.0 

Penjana ini diwarisi dari java.util.Random . Namun, jika kita melihat JavaDoc, kita akan menyedari bahawa hanya ada satu cara menggunakannya - melalui kaedah nextInt . Di atas segalanya, kaedah ini hanya tersedia dengan panggilan nol dan satu parameter. Apa-apa doa lain secara langsung akan menggunakan kaedah java.util.Random

Sebagai contoh, jika kita ingin mendapatkan nombor rawak dalam julat, kita akan menulis:

XoRoShiRo128PlusRandom xoroRandom = new XoRoShiRo128PlusRandom(); int randomWithXoRoShiRo128PlusRandom = xoroRandom.nextInt(max - min) + min;

4. Kesimpulan

Terdapat beberapa cara untuk melaksanakan penjanaan nombor secara rawak. Walau bagaimanapun, tidak ada jalan terbaik. Oleh itu, kita harus memilih yang paling sesuai dengan keperluan kita.

Contoh lengkap boleh didapati di GitHub.