Recherche…


Remarques

Rien n'est vraiment aléatoire et le javadoc appelle donc ces nombres de manière pseudo-aléatoire. Ces nombres sont créés avec un générateur de nombres pseudo-aléatoires .

Nombres aléatoires

Java fournit, dans le cadre du package utils , un générateur de nombres pseudo-aléatoires de base, nommé de manière appropriée Random . Cet objet peut être utilisé pour générer une valeur pseudo-aléatoire comme n'importe quel type de données numérique intégré ( int , float , etc.). Vous pouvez également l'utiliser pour générer une valeur booléenne aléatoire ou un tableau aléatoire d'octets. Un exemple d'utilisation est le suivant:

import java.util.Random;  

...
  
Random random = new Random();
int randInt = random.nextInt();
long randLong = random.nextLong();

double randDouble = random.nextDouble(); //This returns a value between 0.0 and 1.0
float randFloat = random.nextFloat(); //Same as nextDouble

byte[] randBytes = new byte[16];
random.nextBytes(randBytes); //nextBytes takes a user-supplied byte array, and fills it with random bytes. It returns nothing.

REMARQUE: cette classe ne produit que des nombres pseudo-aléatoires de qualité assez faible et ne devrait jamais être utilisée pour générer des nombres aléatoires pour des opérations cryptographiques ou d'autres situations où un caractère aléatoire de qualité supérieure est critique (pour cela, vous souhaitez utiliser la classe SecureRandom , comme indiqué ci-dessous). Une explication de la distinction entre le caractère aléatoire "sécurisé" et "aléatoire" dépasse le cadre de cet exemple.

Nombres aléatoires dans une plage spécifique

La méthode nextInt(int bound) de Random accepte une limite exclusive supérieure, c'est-à-dire un nombre que la valeur aléatoire renvoyée doit être inférieure à. Cependant, seule la méthode nextInt accepte une borne; nextLong , nextDouble etc. ne le font pas.

Random random = new Random();
random.nextInt(1000); // 0 - 999

int number = 10 + random.nextInt(100); // number is in the range of 10 to 109

À partir de Java 1.7, vous pouvez également utiliser ThreadLocalRandom ( source ). Cette classe fournit un générateur de nombres pseudo-aléatoires (PRNG). Notez que la méthode nextInt de cette classe accepte les limites supérieure et inférieure.

import java.util.concurrent.ThreadLocalRandom;

// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
ThreadLocalRandom.current().nextInt(min, max + 1);

Notez que la documentation officielle indique que nextInt(int bound) peut faire des choses étranges lorsque la bound est proche de 2 30 +1 (emphase ajoutée):

L'algorithme est un peu délicat. Il rejette les valeurs qui entraîneraient une distribution inégale (due au fait que 2 ^ 31 n'est pas divisible par n). La probabilité qu'une valeur soit rejetée dépend de n. Le pire des cas est n = 2 ^ 30 + 1, pour lequel la probabilité d'un rejet est 1/2, et le nombre attendu d'itérations avant que la boucle ne se termine est 2.

En d'autres termes, spécifier une limite diminuera (légèrement) les performances de la méthode nextInt , et cette diminution de la performance deviendra plus prononcée à mesure que la bound approche la moitié de la valeur max int.

Génération de nombres pseudo-aléatoires sécurisés par cryptographie

Random et ThreadLocalRandom sont assez bons pour un usage quotidien, mais ils ont un gros problème: ils sont basés sur un générateur de congruence linéaire , un algorithme dont la sortie peut être prédite assez facilement. Ainsi, ces deux classes ne conviennent pas aux utilisations cryptographiques (telles que la génération de clés).

On peut utiliser java.security.SecureRandom dans les situations où un PRNG avec une sortie très difficile à prévoir est requis. Prédire les nombres aléatoires créés par les instances de cette classe est suffisamment difficile pour étiqueter la classe comme étant sécurisée sur le plan cryptographique .

import java.security.SecureRandom;
import java.util.Arrays;

public class Foo {
    public static void main(String[] args) {
        SecureRandom rng = new SecureRandom();
        byte[] randomBytes = new byte[64];
        rng.nextBytes(randomBytes); // Fills randomBytes with random bytes (duh)
        System.out.println(Arrays.toString(randomBytes));
    }
}

En plus d'être sécurisé sur le plan cryptographique, SecureRandom dispose d'une période gigantesque de 2 160 , contre 2 48 pour la période Random . Il a cependant l’inconvénient d’être beaucoup plus lent que Random et d’autres PRNG linéaires tels que Mersenne Twister et Xorshift .

Notez que la mise en œuvre de SecureRandom dépend à la fois de la plate-forme et du fournisseur. Le SecureRandom par défaut (fourni par le fournisseur SUN dans sun.security.provider.SecureRandom ):

  • sur des systèmes de type Unix, dotés de données provenant de /dev/random et / ou /dev/urandom .
  • sur Windows, doté d'appels à CryptGenRandom() dans CryptoAPI .

Sélectionner des nombres aléatoires sans doublons

/**
 * returns a array of random numbers with no duplicates
 * @param range the range of possible numbers for ex. if 100 then it can be anywhere from 1-100
 * @param length the length of the array of random numbers
 * @return array of random numbers with no duplicates.
 */
public static int[] getRandomNumbersWithNoDuplicates(int range, int length){
    if (length<range){
        // this is where all the random numbers
        int[] randomNumbers = new int[length];
        
        // loop through all the random numbers to set them
        for (int q = 0; q < randomNumbers.length; q++){
            
            // get the remaining possible numbers
            int remainingNumbers = range-q;
            
            // get a new random number from the remainingNumbers
            int newRandSpot = (int) (Math.random()*remainingNumbers);
            
            newRandSpot++;
            
            // loop through all the possible numbers
            for (int t = 1; t < range+1; t++){
                
                // check to see if this number has already been taken
                boolean taken = false;
                for (int number : randomNumbers){
                    if (t==number){
                        taken = true;
                        break;
                    }
                }
                
                // if it hasnt been taken then remove one from the spots
                if (!taken){
                    newRandSpot--;
                    
                    // if we have gone though all the spots then set the value
                    if (newRandSpot==0){
                        randomNumbers[q] = t;
                    }
                }
            }
        }
        return randomNumbers;
    } else {
        // invalid can't have a length larger then the range of possible numbers
    }
    return null;
}

La méthode fonctionne en boucle à travers un tableau qui a la taille de la longueur demandée et trouve la longueur restante des nombres possibles. Il définit un nombre aléatoire de ces nombres possibles newRandSpot et trouve ce nombre dans le nombre restant non pris. Cela se fait en parcourant la plage et en vérifiant si ce nombre a déjà été pris.


Par exemple, si la plage est 5 et que la longueur est 3 et que nous avons déjà choisi le nombre 2. Nous avons alors 4 nombres restants, nous obtenons donc un nombre aléatoire compris entre 1 et 4 et nous parcourons la plage (5). que nous avons déjà utilisé (2).

Maintenant, disons que le nombre suivant choisi entre 1 et 4 est 3. Sur la première boucle, nous obtenons 1 qui n'a pas encore été pris, nous pouvons donc en retirer 1 de 3, ce qui fait 2. Maintenant, sur la deuxième boucle, nous obtenons 2 donc nous ne faisons rien. Nous suivons ce schéma jusqu'à ce que nous arrivions à 4 où une fois que nous supprimons 1, il devient 0 et nous définissons donc le nouveau randomNumber sur 4.

Génération de nombres aléatoires avec une graine spécifiée

//Creates a Random instance with a seed of 12345.
Random random = new Random(12345L);

//Gets a ThreadLocalRandom instance
ThreadLocalRandom tlr = ThreadLocalRandom.current();

//Set the instance's seed.
tlr.setSeed(12345L);

L'utilisation de la même graine pour générer des nombres aléatoires renverra les mêmes nombres à chaque fois, donc définir une graine différente pour chaque instance Random est une bonne idée si vous ne voulez pas vous retrouver avec des numéros en double.

System.currentTimeMillis() est une bonne méthode pour obtenir un Long différent pour chaque appel:

Random random = new Random(System.currentTimeMillis());
ThreadLocalRandom.current().setSeed(System.currentTimeMillis());

Générer un nombre aléatoire en utilisant apache-common lang3

Nous pouvons utiliser org.apache.commons.lang3.RandomUtils pour générer des nombres aléatoires en utilisant une seule ligne.

int x = RandomUtils.nextInt(1, 1000);

La méthode nextInt(int startInclusive, int endExclusive) prend une plage.

En dehors de int, nous pouvons générer des nombres long , double , float et bytes aléatoires en utilisant cette classe.

RandomUtils classe RandomUtils contient les méthodes suivantes:

static byte[] nextBytes(int count) //Creates an array of random bytes.
static double nextDouble() //Returns a random double within 0 - Double.MAX_VALUE
static double nextDouble(double startInclusive, double endInclusive) //Returns a random double within the specified range.
static float nextFloat() //Returns a random float within 0 - Float.MAX_VALUE
static float nextFloat(float startInclusive, float endInclusive) //Returns a random float within the specified range.
static int nextInt() //Returns a random int within 0 - Integer.MAX_VALUE
static int nextInt(int startInclusive, int endExclusive) //Returns a random integer within the specified range.
static long nextLong() //Returns a random long within 0 - Long.MAX_VALUE
static long nextLong(long startInclusive, long endExclusive) //Returns a random long within the specified range.


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow