Zufallszahlen in Java generieren

1. Übersicht

In diesem Tutorial werden verschiedene Möglichkeiten zum Generieren von Zufallszahlen in Java untersucht.

2. Verwenden der Java-API

Die Java-API bietet uns verschiedene Möglichkeiten, um unseren Zweck zu erreichen. Lassen Sie uns einige von ihnen sehen.

2.1. java.lang.Math

Die Zufallsmethode der Math- Klasse gibt einen doppelten Wert in einem Bereich von 0,0 (einschließlich) bis 1,0 (exklusiv) zurück. Mal sehen, wie wir es verwenden würden, um eine Zufallszahl in einem bestimmten Bereich zu erhalten, der durch min und max definiert ist :

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

2.2. java.util.Random

Vor Java 1.7 war die beliebteste Methode zum Generieren von Zufallszahlen die Verwendung von nextInt . Es gab zwei Möglichkeiten, diese Methode mit und ohne Parameter zu verwenden. Der Aufruf ohne Parameter gibt einen der int- Werte mit ungefähr gleicher Wahrscheinlichkeit zurück. Es ist also sehr wahrscheinlich, dass wir negative Zahlen erhalten:

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

Wenn wir den netxInt- Aufruf mit dem gebundenen Parameter verwenden, erhalten wir Zahlen innerhalb eines Bereichs:

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

Dies gibt uns eine Zahl zwischen 0 (einschließlich) und Parameter (exklusiv). Der gebundene Parameter muss also größer als 0 sein. Andernfalls erhalten wir eine java.lang.IllegalArgumentException .

Java 8 führte die neuen Ints- Methoden ein, die einen java.util.stream.IntStream zurückgeben. Mal sehen, wie man sie benutzt.

Die ints- Methode ohne Parameter gibt einen unbegrenzten Strom von int- Werten zurück:

IntStream unlimitedIntStream = random.ints();

Wir können auch einen einzelnen Parameter übergeben, um die Stream-Größe zu begrenzen:

IntStream limitedIntStream = random.ints(streamSize);

Und natürlich können wir das Maximum und Minimum für den generierten Bereich festlegen:

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

2.3. java.util.concurrent.ThreadLocalRandom

Java 1.7 brachte uns eine neue und effizientere Möglichkeit, Zufallszahlen über die ThreadLocalRandom- Klasse zu generieren . Dieser hat drei wichtige Unterschiede zur Zufallsklasse :

  • Wir müssen keine neue Instanz von ThreadLocalRandom explizit initiieren . Dies hilft uns, Fehler bei der Erstellung vieler nutzloser Instanzen und der Verschwendung von Garbage Collector-Zeit zu vermeiden
  • Wir können den Startwert für ThreadLocalRandom nicht festlegen , was zu einem echten Problem führen kann. Wenn wir den Startwert setzen müssen, sollten wir diese Art der Erzeugung von Zufallszahlen vermeiden
  • Zufällige Klassen funktionieren in Umgebungen mit mehreren Threads nicht gut

Nun wollen wir sehen, wie es funktioniert:

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

Mit Java 8 oder höher haben wir neue Möglichkeiten. Erstens haben wir zwei Variationen für die nextInt- Methode:

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

Zweitens, und was noch wichtiger ist, können wir die Ints- Methode verwenden:

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

2.4. java.util.SplittableRandom

Java 8 hat uns auch einen wirklich schnellen Generator gebracht - die SplittableRandom- Klasse.

Wie wir im JavaDoc sehen können, ist dies ein Generator zur Verwendung bei parallelen Berechnungen. Es ist wichtig zu wissen, dass die Instanzen nicht threadsicher sind. Wir müssen also vorsichtig sein, wenn wir diese Klasse verwenden.

Wir haben die Methoden nextInt und ints verfügbar . Mit nextInt können wir den oberen und unteren Bereich mithilfe der beiden Parameteraufruf direkt festlegen :

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

Bei dieser Verwendung wird überprüft, ob der Parameter max größer als min ist . Andernfalls erhalten wir eine IllegalArgumentException . Es wird jedoch nicht überprüft, ob wir mit positiven oder negativen Zahlen arbeiten. Jeder der Parameter kann also negativ sein. Wir haben auch Ein-und Null-Parameter-Aufrufe verfügbar. Diese funktionieren auf die gleiche Weise wie zuvor beschrieben.

Wir haben auch die Ints- Methoden zur Verfügung . Dies bedeutet, dass wir leicht einen Strom von int- Werten erhalten können. Zur Verdeutlichung können wir zwischen einem begrenzten und einem unbegrenzten Stream wählen. Für einen begrenzten Stream können wir den oberen und unteren Bereich für den Nummerngenerierungsbereich festlegen:

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

2.5. java.security.SecureRandom

Wenn wir sicherheitsrelevante Anwendungen haben, sollten wir SecureRandom verwenden . Dies ist ein kryptografisch starker Generator. Standardmäßig erstellte Instanzen verwenden keine kryptografisch zufälligen Seeds. Also sollten wir entweder:

  • Setzen Sie den Samen - folglich ist der Samen unvorhersehbar
  • Setzen Sie die Systemeigenschaft java.util.secureRandomSeed auf true

Diese Klasse erbt von java.util.Random . Wir haben also alle Methoden zur Verfügung, die wir oben gesehen haben. Wenn wir beispielsweise einen der int- Werte abrufen müssen, rufen wir nextInt ohne Parameter auf:

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

Wenn wir andererseits den Bereich festlegen müssen, können wir ihn mit dem gebundenen Parameter aufrufen :

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 

Dieser Generator erbt von java.util.Random . Wenn wir uns jedoch JavaDoc ansehen, stellen wir fest, dass es nur einen Weg gibt, es zu verwenden - durch die nextInt- Methode. Diese Methode ist vor allem nur mit den Null- und Ein-Parameter-Aufrufen verfügbar. Alle anderen Aufrufe verwenden direkt die Methoden java.util.Random .

Wenn wir beispielsweise eine Zufallszahl innerhalb eines Bereichs erhalten möchten, schreiben wir:

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

4. Fazit

Es gibt verschiedene Möglichkeiten, die Zufallszahlengenerierung zu implementieren. Es gibt jedoch keinen besten Weg. Folglich sollten wir diejenige wählen, die unseren Bedürfnissen am besten entspricht.

Das vollständige Beispiel finden Sie auf GitHub.