Números aleatorios en Java: Random, rangos, barajar y SecureRandom

Para generar números aleatorios en Java ya no hace falta la vieja fórmula de Math.random() multiplicada y redondeada: desde Java 17, nextInt(origen, límite) da un entero en un rango directamente. Aquí están los casos comunes: dados, rangos, decimales, resultados repetibles, barajar y, para lo que debe ser secreto, SecureRandom.

Rangos, decimales y semilla

import java.util.*;
import java.util.random.RandomGenerator;

void main() {
    var azar = new Random(2026);                     // con semilla: siempre la misma secuencia

    int dado = azar.nextInt(1, 7);                   // de 1 a 6: el límite no se incluye
    int temperatura = azar.nextInt(-5, 36);
    double proporcion = azar.nextDouble();           // de 0.0 a 1.0 (sin incluir 1.0)
    double precio = azar.nextDouble(50, 100);
    boolean moneda = azar.nextBoolean();
    IO.println("dado " + dado + ", temperatura " + temperatura + ", moneda " + (moneda ? "águila" : "sol"));
    IO.println("proporción %.3f, precio %.2f".formatted(proporcion, precio));

    var lista = new ArrayList<>(List.of("Ana", "Luis", "Sofía", "Diego", "Iker"));
    Collections.shuffle(lista, azar);
    IO.println("orden al azar: " + lista);
    IO.println("ganador: " + lista.get(azar.nextInt(lista.size())));

    var otra = new Random(2026);
    IO.println("misma semilla, mismo primer dado: " + (otra.nextInt(1, 7) == dado));

    RandomGenerator moderno = RandomGenerator.of("L64X128MixRandom");
    int d = moderno.nextInt(1, 7);
    IO.println("RandomGenerator: dado entre 1 y 6: " + (d >= 1 && d <= 6));
}
salidadado 6, temperatura -4, moneda águila
proporción 0.849, precio 89.52
orden al azar: [Iker, Sofía, Ana, Diego, Luis]
ganador: Luis
misma semilla, mismo primer dado: true
RandomGenerator: dado entre 1 y 6: true
  • nextInt(origen, límite) incluye el origen y excluye el límite: para un dado, nextInt(1, 7).
  • Con semilla (new Random(2026)) la secuencia es siempre la misma: imprescindible para pruebas y simulaciones que quieras repetir. Sin semilla, cambia en cada ejecución. Las cifras de arriba son las de esa semilla con Java 25.
  • Collections.shuffle baraja una lista; para elegir un elemento, un índice al azar entre 0 y el tamaño.
  • RandomGenerator (Java 17) es la interfaz común de todos los generadores, y permite elegir algoritmos más modernos por nombre.
  • En programas con muchos hilos, ThreadLocalRandom.current() evita que los hilos compitan por el mismo generador.

Para contraseñas y códigos: SecureRandom

import java.security.SecureRandom;

void main() {
    var seguro = new SecureRandom();
    String codigo = "%06d".formatted(seguro.nextInt(1_000_000));
    IO.println("código de verificación de " + codigo.length() + " dígitos (cambia en cada ejecución)");

    String letras = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789";
    var clave = new StringBuilder();
    for (int i = 0; i < 16; i++) clave.append(letras.charAt(seguro.nextInt(letras.length())));
    IO.println("contraseña de " + clave.length() + " caracteres sin letras que se confunden (0/O, 1/l)");
}
salidacódigo de verificación de 6 dígitos (cambia en cada ejecución)
contraseña de 16 caracteres sin letras que se confunden (0/O, 1/l)

Random es predecible: viendo unos cuantos números se pueden calcular los siguientes. Para códigos de verificación, contraseñas temporales o tokens, SecureRandom, que usa el generador del sistema operativo. No imprimimos el código porque cambia en cada ejecución. Lo explicamos con más detalle en seguridad en Java.

Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.