- 1 1. O que você aprenderá neste artigo
- 1.1 1.1 Você entenderá as principais formas de gerar números aleatórios em Java
- 1.2 1.2 Você entenderá as regras de intervalo e equívocos comuns
- 1.3 1.3 Você aprenderá a diferença entre reprodutibilidade e risco
- 1.4 1.4 Você será capaz de escolher “Aleatoriedade segura” vs. “Aleatoriedade perigosa”
- 1.5 1.5 Até iniciantes serão capazes de explicar “Por que esta é a maneira correta”
- 2 2. O que “Números Aleatórios” Significam em Java
- 2.1 2.1 “Random” Não Significa “Perfeitamente Aleatório”
- 2.2 2.2 O que é um Gerador de Números Pseudoaleatórios (PRNG)?
- 2.3 2.3 Quando a “Aleatoriedade Reproduzível” é Útil
- 2.4 2.4 Quando a Aleatoriedade NÃO Deve Ser Reproduzível
- 2.5 2.5 O que é uma “Distribuição Uniforme”? (Noções Básicas de Viés)
- 2.6 2.6 Exemplos Comuns de “Aleatoriedade Tendenciosa” para Iniciantes
- 3 3. Começando Rápido com Math.random()
- 4 4. Entendendo a Classe Central java.util.Random
- 5 5. Controlando Intervalo e Reprodutibilidade com Random
- 6 6. Por Que Random Não É Adequado para Segurança
- 7 7. Usando SecureRandom para Aleatoriedade Crítica de Segurança
- 8 8. APIs Modernas de Aleatoriedade: ThreadLocalRandom e RandomGenerator
- 9 9. Resumo: Escolhendo a API de Aleatoriedade Correta em Java
1. O que você aprenderá neste artigo
Ao tentar trabalhar com “números aleatórios” em Java, você rapidamente encontrará várias opções, como Math.random(), Random e SecureRandom.
Muitas pessoas acabam pensando: “Qual delas devo usar?”
Nesta seção, começaremos com a conclusão e esclareceremos o que você será capaz de fazer ao ler este artigo até o final. Ao entender o panorama geral antes de mergulhar nos mecanismos detalhados e no código, as seções posteriores se tornarão muito mais fáceis de acompanhar.
1.1 Você entenderá as principais formas de gerar números aleatórios em Java
Este artigo explica as principais formas de gerar números aleatórios em Java passo a passo.
Especificamente, você aprenderá:
- Um método simples que pode ser usado imediatamente
- Um método que permite maior controle programático
- Um método para situações em que a segurança é importante
Organizaremos tudo por caso de uso para que seja fácil escolher a abordagem correta.
Isso significa que este artigo serve tanto para:
- Iniciantes que desejam experimentar código de exemplo
- Pessoas que querem ir além de “funciona, então está tudo bem”
A estrutura foi projetada para apoiar ambos os tipos de leitores.
1.2 Você entenderá as regras de intervalo e equívocos comuns
Um dos maiores obstáculos ao trabalhar com números aleatórios é a seleção de intervalo.
Por exemplo:
- Você quer um número aleatório de 0 a 9
- Você quer simular o lançamento de um dado de 1 a 6
- Você quer números aleatórios que incluam valores negativos
Nesses casos, perguntas como as seguintes surgem constantemente:
- O limite superior está incluído?
- O limite inferior está sempre incluído?
- Por que não estou obtendo os valores que esperava?
Este artigo explica isso em um fluxo amigável para iniciantes:
“Por que isso acontece?” → “Como escrever corretamente?”
1.3 Você aprenderá a diferença entre reprodutibilidade e risco
Números aleatórios podem ter requisitos opostos dependendo da situação:
- Você quer resultados diferentes a cada execução
- Você quer reproduzir os mesmos resultados repetidamente
Por exemplo:
- Para testes e depuração, você deseja reproduzir “os mesmos valores aleatórios”
- Para senhas e tokens, você precisa de “valores aleatórios imprevisíveis”
Se você os usar sem entender essa diferença, pode enfrentar problemas como:
- Testes instáveis
- Implementações perigosas para a segurança
Este artigo separa claramente:
“Aleatoriedade que deve ser reproduzível” vs. “Aleatoriedade que não deve ser reproduzível”
1.4 Você será capaz de escolher “Aleatoriedade segura” vs. “Aleatoriedade perigosa”
Java oferece múltiplas opções de geração de números aleatórios que podem parecer semelhantes, mas seus propósitos são completamente diferentes.
- Aleatoriedade adequada para jogos e código de exemplo
- Aleatoriedade que serve para aplicações empresariais
- Aleatoriedade absolutamente necessária para casos de uso de segurança
Se você as usar sem distinguir o propósito, provavelmente acabará com:
- “Parece funcionar, mas na verdade é perigoso”
- “Código que se torna um problema mais tarde”
Este artigo explica os critérios de decisão com razões, na forma:
“Para este caso de uso, use isto.”
1.5 Até iniciantes serão capazes de explicar “Por que esta é a maneira correta”
Em vez de apenas listar exemplos de código, focamos no raciocínio por trás deles, como:
- Por que este método é usado
- Por que este estilo específico está correto
- Por que outras abordagens não são adequadas
Enfatizamos o contexto e a forma de pensar.
Portanto, isso é útil para quem deseja:
- Entender e usar (não apenas memorizar)
- Alcançar um nível em que possa explicar a outros
também.
2. O que “Números Aleatórios” Significam em Java
Antes de gerar números aleatórios em Java, esta seção organiza os fundamentos essenciais que você deve conhecer.
Se você pular isso e apenas copiar o código, quase certamente ficará confuso mais tarde.
2.1 “Random” Não Significa “Perfeitamente Aleatório”
Um equívoco comum entre iniciantes é este:
Números aleatórios gerados em Java não são “perfeitamente aleatórios”.
A maioria dos valores aleatórios usados em Java são descritos com mais precisão como:
- Números calculados de acordo com regras fixas (um algoritmo)
- Eles parecem aleatórios, mas internamente seguem um padrão
Esse tipo de aleatoriedade é chamado de número pseudoaleatório (saída de PRNG).
2.2 O que é um Gerador de Números Pseudoaleatórios (PRNG)?
Um gerador de números pseudoaleatórios é um mecanismo que:
- Começa a partir de um valor inicial (uma semente)
- Repete cálculos matemáticos
- Produz uma sequência que parece aleatória
Os principais benefícios incluem:
- Geração rápida
- A mesma semente reproduz a mesma sequência aleatória
- Fácil de manipular em computadores
Por outro lado, desvantagens incluem:
- Previsível se o algoritmo for conhecido
- Pode ser inadequado para casos de uso de segurança
2.3 Quando a “Aleatoriedade Reproduzível” é Útil
À primeira vista, você pode pensar:
Se os mesmos valores aleatórios aparecem, isso não seria aleatório e, portanto, ruim?
Mas na prática, a aleatoriedade reproduzível é extremamente importante.
Por exemplo:
- Você quer verificar os mesmos resultados toda vez no código de teste
- Você quer reproduzir um relatório de bug
- Você quer comparar resultados de simulação
Nessas situações, é muito mais prático ter:
- Os mesmos valores aleatórios a cada execução
- ao invés de resultados mudando a cada vez
Muitas classes de números aleatórios em Java são projetadas com essa reproducibilidade em mente.
2.4 Quando a Aleatoriedade NÃO Deve Ser Reproduzível
Por outro lado, alguns valores aleatórios nunca devem ser reproduzíveis.
Exemplos típicos incluem:
- Geração de senhas
- Tokens de autenticação
- IDs de sessão
- Chaves de uso único
Se esses valores são:
- Previsíveis
- Reproduzíveis
isso por si só pode levar a um incidente de segurança grave.
É por isso que o Java fornece geradores aleatórios focados em segurança separados dos geradores pseudoaleatórios comuns.
Se você implementar sem entender essa diferença, pode facilmente acabar com:
- Código que “funciona” mas é perigoso
- Código que se torna um problema em revisões ou auditorias
Portanto, certifique‑se de entender este ponto.
2.5 O que é uma “Distribuição Uniforme”? (Noções Básicas de Viés)
Um termo que frequentemente aparece em discussões sobre números aleatórios é distribuição uniforme.
Uma distribuição uniforme significa:
- Cada valor aparece com a mesma probabilidade
Por exemplo:
- Um dado onde 1–6 são igualmente prováveis
- Dígitos 0–9 aparecem uniformemente
Esse estado é uma distribuição uniforme.
As APIs de aleatoriedade do Java são geralmente projetadas assumindo uma distribuição uniforme.
2.6 Exemplos Comuns de “Aleatoriedade Tendenciosa” para Iniciantes
Quando você manualmente “ajusta” números aleatórios, pode acidentalmente introduzir viés.
Exemplos comuns incluem:
- Forçar um intervalo usando
%(o operador resto) - Fazer cast de
doubleparaintno ponto errado - Não entender se os limites são inclusivos
Esses são complicados porque o código ainda roda, o que torna o erro difícil de perceber.
Seções posteriores explicarão, com exemplos concretos:
- Por que o viés ocorre
- Como escrevê‑lo corretamente
para que você possa evitar essas armadilhas.
3. Começando Rápido com Math.random()
A partir daqui, veremos maneiras concretas de gerar números aleatórios em Java. O primeiro método é Math.random(), que é o mais simples e o mais encontrado por iniciantes.
3.1 O que é Math.random()?
Math.random() é um método estático fornecido pelo Java que retorna um valor aleatório double maior ou igual a 0.0 e menor que 1.0.
double value = Math.random();
Quando você executa este código, o valor retornado é:
- maior ou igual a 0.0
- menor que 1.0
Em outras palavras, 1.0 nunca é incluído.
3.2 Por que Math.random() é tão fácil de usar
A maior vantagem do Math.random() é que não requer absolutamente nenhuma configuração.
- Nenhuma instanciação de classe
- Nenhuma declaração de importação
- Utilizável em uma única linha
Devido a isso, é muito conveniente para:
- Exemplos de aprendizado
- Demonstrações simples
- Verificação rápida do fluxo do programa
em esses tipos de situações.
3.3 Gerando Números Inteiros Aleatórios com Math.random()
Em programas reais, você geralmente desejará números inteiros aleatórios
em vez de valores double.
3.3.1 Gerando um Número Aleatório de 0 a 9
int value = (int)(Math.random() * 10);
Os valores produzidos por esse código são:
- 0 ou maior
- 9 ou menor
Veja o porquê:
Math.random()retorna valores de 0.0 a 0.999…- Multiplicar por 10 gera de 0.0 a 9.999…
- Converter para
inttrunca a parte decimal
3.4 Uma Armadilha Comum ao Gerar de 1 a 10
Um erro muito comum entre iniciantes é onde deslocar o valor inicial.
int value = (int)(Math.random() * 10) + 1;
Isso produz números aleatórios que são:
- maiores ou iguais a 1
- menores ou iguais a 10
Se você inverter a ordem e escrever isto em vez disso:
// Common mistake
int value = (int)Math.random() * 10 + 1;
Esse código resulta em:
(int)Math.random()sempre sendo 0- O resultado sempre se tornando 1
Sempre envolva a conversão em parênteses — este é um ponto crítico.
3.5 Vantagens e Limitações do Math.random()
Vantagens
- Extremamente simples
- Baixo custo de aprendizado
- Suficiente para casos de uso pequenos e simples
Limitações
- Não há reprodutibilidade (nenhum controle de semente)
- Nenhum controle interno
- Não adequado para casos de uso de segurança
- Falta de flexibilidade para cenários complexos
Em particular, se você precisar:
- Dos mesmos valores aleatórios em testes
- Controle granular sobre o comportamento
então Math.random() não será suficiente.
3.6 Quando Você Deve Usar Math.random()
Math.random() é mais adequado para:
- Aprendizado inicial de Java
- Código de explicação de algoritmos
- Amostras de verificação simples
Por outro lado, para:
- Aplicações empresariais
- Código de teste
- Lógica relacionada à segurança
você deve escolher um gerador de números aleatórios mais apropriado.
4. Entendendo a Classe Central java.util.Random
Agora vamos avançar um passo além de Math.random() e observar
a classe java.util.Random.
Random é uma classe fundamental que tem sido usada por muitos anos em Java. Ela aparece quando você quer
“controle adequado sobre números aleatórios”.
4.1 O Que é a Classe Random?
Random é uma classe para gerar números pseudo‑aleatórios.
Você a utiliza criando uma instância assim:
import java.util.Random;
Random random = new Random();
int value = random.nextInt();
A maior diferença em relação ao Math.random() é que
o gerador de números aleatórios é tratado como um objeto.
Isso permite que você:
- Reutilize o mesmo gerador
- Mantenha o comportamento consistente
- Gerencie explicitamente a aleatoriedade em seu design
o que não é possível com Math.random().
4.2 Tipos de Valores Aleatórios que Você Pode Gerar com Random
A classe Random fornece métodos adaptados a diferentes casos de uso.
Exemplos comuns incluem:
nextInt(): um valor aleatóriointnextInt(bound): umintde 0 (inclusivo) até bound (exclusivo)nextLong(): um valor aleatóriolongnextDouble(): umdoublede 0.0 (inclusivo) a 1.0 (exclusivo)nextBoolean():trueoufalse
Ao escolher o método correto, você pode gerar valores aleatórios
naturalmente adequados a cada tipo de dado.
5. Controlando Intervalo e Reprodutibilidade com Random
Uma das maiores vantagens de usar java.util.Random é
o controle explícito sobre intervalos e reprodutibilidade.
5.1 Gerando Valores Dentro de um Intervalo Específico
O método mais usado é nextInt(bound).
Random random = new Random();
int value = random.nextInt(10);
Esse código produz valores que são:
- maiores ou iguais a 0
- menores que 10
Portanto, o intervalo resultante é de 0 a 9.
5.2 Deslocando o Intervalo (por exemplo, de 1 a 10)
Para deslocar o intervalo, simplesmente adicione um offset:
int value = random.nextInt(10) + 1;
Isso produz valores de:
- 1 (inclusivo)
- 10 (inclusivo)
Este padrão:
random.nextInt(range) + start
é a forma padrão de gerar valores aleatórios inteiros dentro de um intervalo em Java.
5.3 Gerando Números Aleatórios com Intervalos Negativos
Você também pode gerar intervalos que incluem valores negativos.
Por exemplo, para gerar valores de -5 a 5:
int value = random.nextInt(11) - 5;
Explicação:
nextInt(11)→ 0 a 10- Subtrair 5 → -5 a 5
Esta abordagem funciona de forma consistente independentemente do sinal do intervalo.
5.4 Reprodutibilidade com Seeds
Outra funcionalidade chave do Random é o controle de seed.
Se você especificar uma seed, a sequência aleatória se torna reproduzível:
Random random = new Random(12345);
int value1 = random.nextInt();
int value2 = random.nextInt();
Enquanto o mesmo valor de seed for usado:
- A mesma sequência de valores aleatórios é gerada
Isso é extremamente útil para:
- Testes unitários
- Comparações de simulações
- Depuração de bugs difíceis
Em contraste, Math.random() não permite controle explícito de seed.
6. Por Que Random Não É Adequado para Segurança
Neste ponto, você pode pensar:
Random pode gerar valores imprevisíveis, então não é adequado para segurança?
Essa é uma compreensão muito comum e errônea.
6.1 Previsibilidade É o Problema Central
java.util.Random usa um algoritmo determinístico.
Isso significa:
- Se o algoritmo for conhecido
- Se valores de saída suficientes forem observados
então valores futuros podem ser previstos.
Para jogos ou simulações, isso não é um problema.
Para segurança, isso é uma falha crítica.
6.2 Exemplos Concretos de Uso Perigoso
Usar Random para o seguinte é perigoso:
- Geração de senhas
- Chaves de API
- Identificadores de sessão
- Tokens de autenticação
Mesmo que os valores “pareçam aleatórios”, eles não são cryptograficamente seguros.
6.3 A Diferença Chave Entre “Aparência Aleatória” e “Seguro”
A distinção crítica é esta:
- Random : rápido, reproduzível, previsível em teoria
- Aleatório seguro : imprevisível, resistente a análises
A aleatoriedade focada em segurança deve ser projetada sob a suposição de que:
- O atacante conhece o algoritmo
- O atacante pode observar saídas
Random não atende a esse requisito.
É por isso que o Java fornece uma classe separada especificamente para casos de uso de segurança.
7. Usando SecureRandom para Aleatoriedade Crítica de Segurança
Quando a aleatoriedade deve ser imprevisível e resistente a ataques,
o Java fornece java.security.SecureRandom.
Esta classe é projetada especificamente para casos de uso sensíveis à segurança.
7.1 O Que Torna SecureRandom Diferente?
SecureRandom difere de Random em seus objetivos de design.
- Usa algoritmos criptograficamente fortes
- Obtém entropia de múltiplas fontes do sistema
- Projetado para ser imprevisível mesmo se saídas forem observadas
Diferentemente de Random, o estado interno de SecureRandom é praticamente irreversível.
7.2 Uso Básico de SecureRandom
O uso é similar ao de Random, mas a intenção é muito diferente.
import java.security.SecureRandom;
SecureRandom secureRandom = new SecureRandom();
int value = secureRandom.nextInt(10);
Isso produz valores de:
- 0 (inclusivo)
- 10 (exclusivo)
A API é intencionalmente similar para que possa substituir Random quando necessário.
7.3 Quando Você Deve Usar SecureRandom
Você deve usar SecureRandom para:
- Geração de senhas
- IDs de sessão
- Tokens de autenticação
- Chaves criptográficas
Nesses cenários, usar Random não é “levemente arriscado” — é incorreto.
O custo de desempenho de SecureRandom é intencional e aceitável para segurança.
8. APIs Modernas de Aleatoriedade: ThreadLocalRandom e RandomGenerator
Versões recentes do Java fornecem APIs de aleatoriedade mais avançadas para abordar problemas de desempenho e design.
8.1 ThreadLocalRandom: Aleatoriedade para Multithreading
ThreadLocalRandom é otimizado para ambientes multithread.
Em vez de compartilhar uma única instância de Random, cada thread usa seu próprio gerador.
int value = java.util.concurrent.ThreadLocalRandom.current().nextInt(1, 11);
Isso gera valores de 1 (inclusivo) a 11 (exclusivo).
As vantagens incluem:
- Sem contenção entre threads
- Melhor desempenho sob concorrência
- APIs baseadas em intervalos claros
Para processamento paralelo, isso geralmente é preferível ao Random.
8.2 RandomGenerator: Uma Interface Unificada (Java 17+)
RandomGenerator é uma interface introduzida para unificar a geração de números aleatórios.
Ela permite:
- Trocar algoritmos facilmente
- Escrever código independente da implementação
- Design mais preparado para o futuro
import java.util.random.RandomGenerator; RandomGenerator generator = RandomGenerator.getDefault(); int value = generator.nextInt(10);
Esta abordagem é recomendada para bases de código Java modernas.
9. Resumo: Escolhendo a API de Aleatoriedade Correta em Java
Java fornece várias APIs de números aleatórios porque
“aleatoriedade” tem diferentes significados dependendo do contexto.
9.1 Guia Rápido de Decisão
Math.random(): aprendizado, demonstrações simplesRandom: testes, simulações, comportamento reproduzívelThreadLocalRandom: aplicações multithreadRandomGenerator: design moderno e flexívelSecureRandom: senhas, tokens, segurança
Escolher a errada pode não causar erros imediatos,
mas pode gerar problemas sérios mais tarde.
9.2 O Princípio Fundamental a Lembrar
A principal lição é a seguinte:
Aleatoriedade é uma decisão de design, não apenas uma chamada de função.
Ao entender a intenção por trás de cada API, você pode escrever código Java que seja:
- Correto
- Manutenível
- Seguro
e adequado para aplicações do mundo real.

