Java Language
Generación de números aleatorios
Buscar..
Observaciones
Nada es realmente aleatorio y, por lo tanto, el javadoc llama a esos números pseudoaleatorios. Esos números se crean con un generador de números pseudoaleatorios .
Números pseudoaleatorios
Java proporciona, como parte del paquete utils
, un generador básico de números pseudoaleatorios, denominado apropiadamente Random
. Este objeto se puede usar para generar un valor pseudoaleatorio como cualquiera de los tipos de datos numéricos incorporados ( int
, float
, etc.). También puede usarlo para generar un valor booleano aleatorio, o una matriz aleatoria de bytes. Un ejemplo de uso es el siguiente:
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.
NOTA: Esta clase solo produce números pseudoaleatorios de baja calidad, y nunca debe usarse para generar números aleatorios para operaciones criptográficas u otras situaciones en las que la aleatoriedad de mayor calidad es crítica (para eso, desearía usar la clase SecureRandom
, como se indica a continuación). Una explicación para la distinción entre aleatoriedad "segura" e "insegura" está fuera del alcance de este ejemplo.
Números pseudoaleatorios en rango específico
El método nextInt(int bound)
de Random
acepta un límite exclusivo superior, es decir, un número que el valor aleatorio devuelto debe ser menor que. Sin embargo, solo el método nextInt
acepta un límite; nextLong
, nextDouble
etc no lo hacen.
Random random = new Random();
random.nextInt(1000); // 0 - 999
int number = 10 + random.nextInt(100); // number is in the range of 10 to 109
A partir de Java 1.7, también puede utilizar ThreadLocalRandom
( fuente ). Esta clase proporciona un PRNG seguro para subprocesos (generador de números pseudoaleatorios). Tenga en cuenta que el método nextInt
de esta clase acepta un límite superior e inferior.
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);
Tenga en cuenta que la documentación oficial indica que nextInt(int bound)
puede hacer cosas raras cuando el bound
está cerca de 2 30 +1 (énfasis agregado):
El algoritmo es un poco complicado. Rechaza los valores que darían como resultado una distribución desigual (debido al hecho de que 2 ^ 31 no es divisible por n). La probabilidad de que un valor sea rechazado depende de n. El caso más desfavorable es n = 2 ^ 30 + 1, para el cual la probabilidad de un rechazo es 1/2, y el número esperado de iteraciones antes de que finalice el bucle es 2.
En otras palabras, especificar un límite disminuirá (levemente) el rendimiento del método nextInt
, y esta disminución del rendimiento será más pronunciada a medida que el bound
aproxime a la mitad del valor int máximo.
Generación de números pseudoaleatorios criptográficamente seguros.
Random
y ThreadLocalRandom
son lo suficientemente buenos para el uso diario, pero tienen un gran problema: se basan en un generador lineal congruente , un algoritmo cuya salida se puede predecir con bastante facilidad. Por lo tanto, estas dos clases no son adecuadas para usos criptográficos (como la generación de claves).
Uno puede usar java.security.SecureRandom
en situaciones donde se requiere un PRNG con una salida que sea muy difícil de predecir. Predecir los números aleatorios creados por las instancias de esta clase es lo suficientemente difícil como para etiquetar la clase como criptográficamente segura .
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));
}
}
Además de ser criptográficamente seguro, SecureRandom
tiene un período gigantesco de 2 160 , comparado con el período de Random
de 2 48 . Sin embargo, tiene un inconveniente de ser considerablemente más lento que el Random
y otros PRNG lineales como Mersenne Twister y Xorshift .
Tenga en cuenta que la implementación de SecureRandom depende tanto de la plataforma como del proveedor. El SecureRandom
predeterminado (dado por el proveedor de SUN
en sun.security.provider.SecureRandom
):
- en sistemas similares a Unix, sembrados con datos de
/dev/random
y / o/dev/urandom
. - en Windows, sembradas con llamadas a
CryptGenRandom()
en CryptoAPI .
Seleccionar números aleatorios sin duplicados
/**
* 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;
}
El método funciona en bucle a través de una matriz que tiene el tamaño de la longitud solicitada y encuentra la longitud restante de los números posibles. Establece un número aleatorio de esos posibles números newRandSpot
y encuentra ese número dentro del número no tomado que queda. Lo hace recorriendo el rango y comprobando si ese número ya se ha tomado.
Por ejemplo, si el rango es 5 y la longitud es 3 y ya hemos elegido el número 2. Luego tenemos 4 números restantes, así que obtenemos un número aleatorio entre 1 y 4 y pasamos por el rango (5) saltando cualquier número que ya hemos utilizado (2).
Ahora digamos que el siguiente número elegido entre 1 y 4 es 3. En el primer bucle obtenemos 1 que aún no se ha tomado, por lo que podemos eliminar 1 de 3, lo que hace que sea 2. Ahora, en el segundo bucle obtenemos 2 que ha sido tomado así que no hacemos nada. Seguimos este patrón hasta que llegamos a 4, donde una vez que eliminamos 1, se convierte en 0, por lo que establecemos el nuevo número aleatorio en 4.
Generando números aleatorios con una semilla especificada
//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);
Usar la misma semilla para generar números aleatorios devolverá los mismos números cada vez, por lo que establecer una semilla diferente para cada instancia Random
es una buena idea si no quiere terminar con números duplicados.
Un buen método para obtener un Long
que es diferente para cada llamada es System.currentTimeMillis()
:
Random random = new Random(System.currentTimeMillis());
ThreadLocalRandom.current().setSeed(System.currentTimeMillis());
Generando números aleatorios usando apache-common lang3
Podemos usar org.apache.commons.lang3.RandomUtils
para generar números aleatorios usando una sola línea.
int x = RandomUtils.nextInt(1, 1000);
El método nextInt(int startInclusive, int endExclusive)
toma un rango.
Aparte de int, podemos generar aleatorios long
, double
, float
y bytes
utilizando esta clase.
RandomUtils
clase RandomUtils
contiene los siguientes métodos:
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.