O fatorial de um número inteiro n (escrito n!) é o produto de todos os inteiros de 1 até n. Por definição, 0! = 1. Exemplo: 5! = 5 × 4 × 3 × 2 × 1 = 120.
É um exercício clássico porque permite praticar três formas diferentes de pensar um problema. Vamos a elas.
1. Com laço for
A forma mais direta: começamos com 1 e multiplicamos acumulando o resultado.
public static long fatorialIterativo(int n) {
if (n < 0) throw new IllegalArgumentException("n não pode ser negativo");
long resultado = 1;
for (int i = 2; i <= n; i++) {
resultado *= i;
}
return resultado;
}É rápida, não consome memória extra e é a escolha certa para produção.
2. Com recursão
A definição matemática é recursiva: n! = n × (n − 1)!. O código fica quase igual à fórmula:
public static long fatorialRecursivo(int n) {
if (n < 0) throw new IllegalArgumentException("n não pode ser negativo");
if (n <= 1) return 1; // caso base
return n * fatorialRecursivo(n - 1); // passo recursivo
}Elegante e ótima para aprender recursão. O cuidado: cada chamada ocupa espaço na pilha. Para o fatorial isso não é problema (o long estoura muito antes da pilha), mas em outros algoritmos recursivos profundos pode gerar StackOverflowError.
3. Com Streams
Com a API de Streams, o fatorial vira “gere os números de 1 a n e multiplique todos”:
public static long fatorialStream(int n) {
if (n < 0) throw new IllegalArgumentException("n não pode ser negativo");
return LongStream.rangeClosed(1, n)
.reduce(1, (a, b) -> a * b);
}Uma linha declarativa, que comunica bem a intenção. Se você ainda não domina lambdas, veja o artigo Expressões Lambda em Java.
Atenção aos limites
O fatorial cresce muito rápido. Os tipos primitivos chegam ao limite cedo:
| Tipo | Maior fatorial que cabe |
|---|---|
int | 12! = 479.001.600 |
long | 20! = 2.432.902.008.176.640.000 |
Passou disso, o resultado estoura silenciosamente e você recebe um número errado, sem erro nenhum. Para valores maiores, use BigInteger:
public static BigInteger fatorialGrande(int n) {
BigInteger resultado = BigInteger.ONE;
for (int i = 2; i <= n; i++) {
resultado = resultado.multiply(BigInteger.valueOf(i));
}
return resultado;
}
System.out.println(fatorialGrande(30));
// 265252859812191058636308480000000Qual escolher?
- Laço: o padrão no dia a dia — simples e eficiente.
- Recursão: para estudar e para problemas naturalmente recursivos.
- Streams: quando a leitura declarativa combina com o resto do código.
- BigInteger: sempre que n puder passar de 20.