Java Números Aleatórios

Jogar um dado, sortear quem apresenta o trabalho, embaralhar perguntas, criar o número secreto de um jogo de adivinhação: tudo isso precisa de números aleatórios, que o programa "tira da cartola" e que mudam a cada execução. O Java tem várias formas de fazer isso; nesta aula você vai aprender as principais e quando usar cada uma.

Você vai aprender
  • Como transformar o Math.random() num dado de 1 a 6.
  • A classe Random: nextInt, nextDouble, nextBoolean.
  • A fórmula para sortear em qualquer faixa, de min a max.
  • O que é a semente, e por que new Random(42) sempre dá a mesma sequência.
  • ThreadLocalRandom e RandomGenerator Java 17+.
  • Os erros comuns: import esquecido, bound must be positive, o (int) no lugar errado.

A ideia: uma máquina de sortear

O computador não joga dados de verdade. Ele usa uma fórmula que, a partir de um número inicial, produz uma sequência que parece aleatória: sem padrão visível, com todos os valores aparecendo com a mesma frequência. Por isso o nome técnico é pseudoaleatório ("falso aleatório"). Para jogos, sorteios e simulações, é perfeito.

Pense num baralho enorme, já embaralhado, de onde você vai tirando cartas pela ordem. Quem olha não consegue prever a próxima carta; mas, se alguém embaralhar exatamente do mesmo jeito, a ordem será a mesma. Esse "jeito de embaralhar" é a semente, que você vai ver mais adiante.


O jeito mais simples: Math.random()

Você conheceu o Math.random() na aula Math: ele devolve um double entre 0.0 (pode sair) e 1.0 (nunca sai). Para virar um dado, são três passos:

public class Main {
    public static void main(String[] args) {
        double sorteio = Math.random();
        System.out.println(sorteio);
        System.out.println(sorteio * 6);
        System.out.println((int) (sorteio * 6));
        int dado = (int) (Math.random() * 6) + 1;
        System.out.println("Dado: " + dado);
    }
}
$ java Main.java
0.8942632483583696     « um número entre 0 e 1
5.365579490150218      « vezes 6: entre 0 e 5,999…
5                      « (int) corta a parte decimal: 0, 1, 2, 3, 4 ou 5
Dado: 4                « mais 1: entre 1 e 6 (outro sorteio, por isso outro valor)
$ java Main.java
0.10267241060837118
0.6160344636502271
0
Dado: 3                « cada execução, números diferentes
PassoExpressãoValores possíveis
1. SortearMath.random()0.0 até 0.999…
2. EsticarMath.random() * 60.0 até 5.999…
3. Cortar(int) (Math.random() * 6)0, 1, 2, 3, 4, 5
4. Deslocar(int) (Math.random() * 6) + 11, 2, 3, 4, 5, 6

Os parênteses em volta de Math.random() * 6 são essenciais: o (int) tem de cortar o resultado da multiplicação. Sem eles, o dado sempre dá 1 (veja "Quando dá errado").

Brinque com o código: clique em Rodar várias vezes e veja o dado mudar. Depois transforme-o num dado de 20 faces (de 1 a 20).

public class Main {
    public static void main(String[] args) {
        int dado = (int) (Math.random() * 6) + 1;
        System.out.println("Dado: " + dado);
    }
}

A classe Random

O Math.random() só dá double, e a conta para virar inteiro é chata. A classe Random ("aleatório") é uma máquina de sortear mais completa, com métodos prontos para cada tipo.

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        Random r = new Random();
        System.out.println(r.nextInt(6) + 1);
        System.out.println(r.nextInt(1, 7));
        System.out.println(r.nextInt());
        System.out.println(r.nextDouble());
        System.out.println(r.nextBoolean());
    }
}
$ java Main.java
3
3
78269670
0.6057460381527114
false
import java.util.Random;
Random mora no pacote java.util ("utilidades"), que não é carregado automaticamente como o java.lang do Math. A linha import ("importar"), no topo do arquivo, diz ao javac onde achar a classe. Mais em Pacotes e import.
Random r = new Random();
Cria a máquina de sortear e guarda na variável r. O new ("novo") cria um objeto; você vai entender objetos a fundo em Classes e Objetos. Por enquanto: crie uma máquina e use-a para todos os sorteios.
r.nextInt(6)
"O próximo inteiro" de 0 até 5: o número entre parênteses (o bound, "limite") nunca sai. Por isso o + 1, para o dado ir de 1 a 6.
r.nextInt(1, 7)
Inteiro de 1 (incluído) até 7 (excluído), ou seja, de 1 a 6, sem conta extra. Esta forma com dois números existe desde o Java 17.
r.nextInt()
Sem limite: qualquer int, inclusive negativo. Raramente é o que você quer.
r.nextDouble()
Um double entre 0.0 e 1.0, como o Math.random().
r.nextBoolean()
true ou false, meio a meio: cara ou coroa.
O limite de cima não entra

Em nextInt(6) e nextInt(1, 7), o último número fica de fora, a mesma regra do substring (veja Métodos de String). Esquecer isso gera o erro mais comum com aleatórios: um dado que nunca tira 6.


Sortear numa faixa: de min a max

Para sortear um inteiro de min a max, incluindo os dois, use uma destas formas:

FormaDesde
r.nextInt(max - min + 1) + minSempre (funciona em qualquer versão)
r.nextInt(min, max + 1)Java 17
(int) (Math.random() * (max - min + 1)) + minSempre, sem Random

Por que max - min + 1? Porque é a quantidade de números da faixa. De 10 a 20 há 11 números (10, 11, …, 20): 20 - 10 + 1 = 11. nextInt(11) sorteia de 0 a 10; somando 10, fica de 10 a 20.

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        Random r = new Random();
        int min = 10;
        int max = 20;
        for (int i = 0; i < 8; i++) {
            int n = r.nextInt(max - min + 1) + min;
            System.out.print(n + " ");
        }
        System.out.println();
        for (int i = 0; i < 8; i++) {
            System.out.print(r.nextInt(min, max + 1) + " ");
        }
        System.out.println();
    }
}
$ java Main.java
20 16 20 16 20 17 15 10       « o 10 e o 20 aparecem: os dois extremos entram
11 12 15 20 11 16 16 17

O for repete o sorteio 8 vezes; você vai estudá-lo em for. Repare que o 10 e o 20 apareceram: a faixa inclui as duas pontas.


A semente: a mesma sequência sempre

Quando você cria um new Random() sem nada entre os parênteses, o Java escolhe uma semente (seed) diferente a cada vez, baseada no relógio e em outros detalhes. Por isso cada execução dá números diferentes. Mas você pode escolher a semente:

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        Random r = new Random(42);
        System.out.println(r.nextInt(100));
        System.out.println(r.nextInt(100));
        System.out.println(r.nextInt(100));
        System.out.println(r.nextInt(100));
        System.out.println(r.nextInt(100));
    }
}
$ java Main.java
30
63
48
84
70
$ java Main.java
30          « exatamente a mesma sequência
63
48
84
70

Com a semente 42, a sequência é sempre 30, 63, 48, 84, 70, em qualquer execução e em qualquer computador com Java (a fórmula do Random é fixa na especificação). Dentro do mesmo programa também: duas máquinas com a mesma semente "andam juntas".

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        Random a = new Random(42);
        Random b = new Random(42);
        Random c = new Random(7);
        System.out.println("a: " + (a.nextInt(6) + 1) + " " + (a.nextInt(6) + 1) + " " + (a.nextInt(6) + 1));
        System.out.println("b: " + (b.nextInt(6) + 1) + " " + (b.nextInt(6) + 1) + " " + (b.nextInt(6) + 1));
        System.out.println("c: " + (c.nextInt(6) + 1) + " " + (c.nextInt(6) + 1) + " " + (c.nextInt(6) + 1));
    }
}
$ java Main.java
a: 3 4 1     « semente 42
b: 3 4 1     « semente 42 de novo: os mesmos dados
c: 5 3 4     « outra semente, outra sequência

Para que serve um sorteio que sempre dá o mesmo resultado?

  • Testar: se o seu jogo tem um erro que só aparece com certos dados, a semente fixa permite repetir a partida exata até achar o problema.
  • Reproduzir: simulações científicas e geradores de mapas de jogos (o "seed" do Minecraft é isso) usam sementes para recriar o mesmo resultado.
  • Ensinar: é por isso que as missões abaixo usam sementes; assim o editor do guia sabe que resposta esperar.
Não use Random para segurança

Como a sequência pode ser prevista por quem descobre a semente, Random não serve para senhas, códigos de verificação ou tokens. Para isso existe java.security.SecureRandom, que é usado do mesmo jeito (new SecureRandom().nextInt(10)), mas é imprevisível.

Missão: crie um Random com a semente 2026 e role um dado de 1 a 6 com nextInt. Com essa semente, o primeiro dado é sempre 6: a saída deve ser Dado: 6.

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        // crie o Random com semente 2026 e role o dado
    }
}
import java.util.Random;

public class Main {
    public static void main(String[] args) {
        Random r = new Random(2026);
        int dado = r.nextInt(6) + 1;
        System.out.println("Dado: " + dado);
    }
}

Sortear um item: nomes, cara ou coroa

Para sortear um elemento de uma lista, sorteie a posição. Num array de 5 nomes, as posições vão de 0 a 4, e r.nextInt(alunos.length) sorteia exatamente nessa faixa:

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        String[] alunos = {"Ana", "Bruno", "Carla", "Diego", "Elisa"};
        Random r = new Random();
        int posicao = r.nextInt(alunos.length);
        System.out.println("Quem apresenta hoje: " + alunos[posicao]);
        String moeda = r.nextBoolean() ? "cara" : "coroa";
        System.out.println("Moeda: " + moeda);
    }
}
$ java Main.java
Quem apresenta hoje: Ana
Moeda: cara
$ java Main.java
Quem apresenta hoje: Elisa
Moeda: coroa
String[] alunos = {…}
Um array com 5 nomes, nas posições 0 a 4.
r.nextInt(alunos.length)
alunos.length é 5, então sorteia de 0 a 4: sempre uma posição válida, mesmo que você acrescente nomes.
r.nextBoolean() ? "cara" : "coroa"
O operador ternário: "se o sorteio deu true, cara; senão, coroa". Ele tem aula própria: Operador Ternário.

Para embaralhar uma lista inteira (a ordem das perguntas de uma prova, por exemplo), existe Collections.shuffle, visto em A Classe Collections.


ThreadLocalRandom e RandomGenerator

Você vai encontrar mais duas formas em código moderno:

import java.util.concurrent.ThreadLocalRandom;
import java.util.random.RandomGenerator;

public class Main {
    public static void main(String[] args) {
        int dado = ThreadLocalRandom.current().nextInt(1, 7);
        System.out.println("ThreadLocalRandom: " + dado);
        RandomGenerator gerador = RandomGenerator.getDefault();
        System.out.println("RandomGenerator: " + gerador.nextInt(1, 7));
        RandomGenerator outro = RandomGenerator.of("L64X128MixRandom");
        System.out.println("L64X128MixRandom: " + outro.nextInt(1, 7));
        System.out.println(gerador.getClass().getSimpleName());
    }
}
$ java Main.java
ThreadLocalRandom: 5
RandomGenerator: 1
L64X128MixRandom: 6
L32X64MixRandom          « o algoritmo que o getDefault() escolheu
ThreadLocalRandom.current()
Uma máquina de sortear que o Java já deixa pronta, sem new. Foi feita para programas que fazem várias coisas ao mesmo tempo (threads), onde cada parte do programa ganha a sua própria máquina e ninguém espera ninguém. Também é prática em programas simples: uma linha só. Não aceita semente.
RandomGenerator
Java 17+ Uma "família" de geradores com a mesma cara (nextInt, nextDouble…). O próprio Random faz parte dela. getDefault() entrega um bom gerador moderno (no JDK 25, o L32X64MixRandom); of("nome") escolhe um algoritmo pelo nome.
Você quer…Use
Um sorteio rápido, sem importMath.random()
Vários sorteios de inteiros, booleanos, decimaisRandom
Repetir a mesma sequência (testes, missões)new Random(semente)
Uma linha só, ou um programa com threadsThreadLocalRandom.current()
Escolher o algoritmo, código novo (Java 17+)RandomGenerator
Senhas, códigos de segurançaSecureRandom

Quando dá errado

error: cannot find symbol … symbol: class Random

Este código tem um erro de propósito.

public class Main {
    public static void main(String[] args) {
        Random r = new Random();
        System.out.println(r.nextInt(6));
    }
}
$ javac Main.java
Main.java:3: error: cannot find symbol
        Random r = new Random();
        ^
  symbol:   class Random
  location: class Main
Main.java:3: error: cannot find symbol
        Random r = new Random();
                       ^
  symbol:   class Random
  location: class Main
2 errors

O que aconteceu: faltou o import. Sem ele, o javac não sabe que Random está em java.util. Os dois erros apontam os dois lugares onde o nome aparece.

Como resolver: coloque import java.util.Random; na primeira linha do arquivo, antes de public class. (Ou escreva o nome completo: java.util.Random r = new java.util.Random();.)

IllegalArgumentException: bound must be positive

Este código tem um erro de propósito.

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        Random r = new Random();
        int quantidade = 0;
        System.out.println(r.nextInt(quantidade));
    }
}
$ java Main.java
Exception in thread "main" java.lang.IllegalArgumentException: bound must be positive
	at java.base/java.util.Random.nextInt(Random.java:551)
	at Main.main(Main.java:7)

O que aconteceu: o limite do nextInt tem de ser positivo ("o limite deve ser positivo"); não dá para sortear entre zero números. Acontece quando a lista está vazia (nextInt(alunos.length) com nenhum aluno) ou quando min e max estão trocados na fórmula.

Como resolver: confira a conta do limite e, se a lista pode estar vazia, teste antes com um if.

O dado sempre dá 1

Este código tem um erro de propósito.

public class Main {
    public static void main(String[] args) {
        int dado = (int) Math.random() * 6 + 1;
        System.out.println(dado);
    }
}
$ java Main.java
1
$ java Main.java
1

O que aconteceu: o (int) vale só para o que está logo depois dele: Math.random(). Um número entre 0 e 0,999…, cortado, é sempre 0; 0 * 6 + 1 é sempre 1. Não há erro de compilação: o programa simplesmente não sorteia nada.

Como resolver: parênteses em volta da multiplicação: (int) (Math.random() * 6) + 1. Ou use Random e nextInt(1, 7), que não tem essa armadilha.

error: incompatible types: possible lossy conversion from double to int

Este código tem um erro de propósito.

public class Main {
    public static void main(String[] args) {
        int dado = Math.random() * 6 + 1;
        System.out.println(dado);
    }
}
$ javac Main.java
Main.java:3: error: incompatible types: possible lossy conversion from double to int
        int dado = Math.random() * 6 + 1;
                                     ^
1 error

O que aconteceu: a conta inteira é double (por causa do Math.random()) e não cabe num int sem perder a parte decimal.

Como resolver: (int) (Math.random() * 6) + 1.

O dado nunca tira 6

O que aconteceu: foi usado r.nextInt(1, 6) ou r.nextInt(6) sem o + 1. O limite de cima não entra.

Como resolver: r.nextInt(1, 7) ou r.nextInt(6) + 1.


Referência

EscritaSorteia
Math.random()double em [0.0, 1.0)
(int) (Math.random() * n)int de 0 a n-1
new Random()Cria um gerador (semente diferente a cada vez)
new Random(42)Cria um gerador com semente fixa (sequência repetível)
r.nextInt(n)int de 0 a n-1
r.nextInt(a, b)int de a a b-1 (Java 17+)
r.nextInt(max - min + 1) + minint de min a max
r.nextDouble()double em [0.0, 1.0)
r.nextBoolean()true ou false
ThreadLocalRandom.current().nextInt(a, b)int de a a b-1
RandomGenerator.getDefault()Um gerador moderno (Java 17+)

Exercícios

Missão final: com new Random(2026), sorteie três números de 10 a 20 (incluindo os dois) e mostre-os numa linha, separados por espaço. Com essa semente, a saída é sempre 17 18 14.

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        int min = 10;
        int max = 20;
        // crie o Random e sorteie três números
    }
}
import java.util.Random;

public class Main {
    public static void main(String[] args) {
        Random r = new Random(2026);
        int min = 10;
        int max = 20;
        int a = r.nextInt(max - min + 1) + min;
        int b = r.nextInt(max - min + 1) + min;
        int c = r.nextInt(max - min + 1) + min;
        System.out.println(a + " " + b + " " + c);
    }
}

1. Dado de 12 faces

Complete para sortear de 1 a 12:

int d = r.nextInt() + 1;

2. A faixa

Complete para sortear de 50 a 100 (incluindo os dois) com nextInt(a, b):

int n = r.nextInt(50, );

3. O import

Complete a linha que permite usar Random:

import ;

4. O que new Random(42) garante?

5. Quais valores r.nextInt(5) pode devolver?

6. Para gerar o código de recuperação de senha de um site, use…


Resumo

  • Os números são pseudoaleatórios: vêm de uma fórmula que parte de uma semente.
  • Math.random() dá um double em [0, 1); para um dado: (int) (Math.random() * 6) + 1, com os parênteses.
  • Random (com import java.util.Random;): nextInt(n) dá de 0 a n-1; nextInt(a, b) dá de a a b-1; o limite de cima nunca entra.
  • De min a max: r.nextInt(max - min + 1) + min.
  • new Random(semente) repete sempre a mesma sequência: ótimo para testes, péssimo para segurança (use SecureRandom).
  • ThreadLocalRandom.current() e RandomGenerator (Java 17+) são as opções modernas.