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.
- 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
minamax. - O que é a semente, e por que
new Random(42)sempre dá a mesma sequência. ThreadLocalRandomeRandomGeneratorJava 17+.- Os erros comuns:
importesquecido,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
| Passo | Expressão | Valores possíveis |
|---|---|---|
| 1. Sortear | Math.random() | 0.0 até 0.999… |
| 2. Esticar | Math.random() * 6 | 0.0 até 5.999… |
| 3. Cortar | (int) (Math.random() * 6) | 0, 1, 2, 3, 4, 5 |
| 4. Deslocar | (int) (Math.random() * 6) + 1 | 1, 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;
Randommora no pacotejava.util("utilidades"), que não é carregado automaticamente como ojava.langdoMath. A linhaimport("importar"), no topo do arquivo, diz aojavaconde achar a classe. Mais em Pacotes e import.- Random r = new Random();
- Cria a máquina de sortear e guarda na variável
r. Onew("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
0até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
doubleentre 0.0 e 1.0, como oMath.random(). - r.nextBoolean()
trueoufalse, meio a meio: cara ou coroa.
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:
| Forma | Desde |
|---|---|
r.nextInt(max - min + 1) + min | Sempre (funciona em qualquer versão) |
r.nextInt(min, max + 1) | Java 17 |
(int) (Math.random() * (max - min + 1)) + min | Sempre, 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.
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óprioRandomfaz parte dela.getDefault()entrega um bom gerador moderno (no JDK 25, oL32X64MixRandom);of("nome")escolhe um algoritmo pelo nome.
| Você quer… | Use |
|---|---|
Um sorteio rápido, sem import | Math.random() |
| Vários sorteios de inteiros, booleanos, decimais | Random |
| Repetir a mesma sequência (testes, missões) | new Random(semente) |
| Uma linha só, ou um programa com threads | ThreadLocalRandom.current() |
| Escolher o algoritmo, código novo (Java 17+) | RandomGenerator |
| Senhas, códigos de segurança | SecureRandom |
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.
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 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
| Escrita | Sorteia |
|---|---|
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) + min | int 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:
2. A faixa
Complete para sortear de 50 a 100 (incluindo os dois) com nextInt(a, b):
3. O import
Complete a linha que permite usar Random:
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á umdoubleem [0, 1); para um dado:(int) (Math.random() * 6) + 1, com os parênteses.Random(comimport 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
minamax:r.nextInt(max - min + 1) + min. new Random(semente)repete sempre a mesma sequência: ótimo para testes, péssimo para segurança (useSecureRandom).ThreadLocalRandom.current()eRandomGenerator(Java 17+) são as opções modernas.