Tipos primitivos: visão geral e quando usar
Em Java, tipos primitivos são tipos de dados básicos, armazenados de forma eficiente e com comportamento previsível. Eles não são objetos e possuem tamanhos fixos. Use primitivos quando você precisa de desempenho, simplicidade e valores numéricos/lógicos diretos.
| Tipo | Tamanho | Intervalo (aprox.) | Uso típico |
|---|---|---|---|
boolean | JVM-dependente (conceitual) | true/false | Flags, validações, condições |
byte | 8 bits | -128 a 127 | Dados binários, buffers, I/O, protocolos |
short | 16 bits | -32.768 a 32.767 | Economia de memória em arrays grandes (raro) |
int | 32 bits | -2.147.483.648 a 2.147.483.647 | Inteiros em geral (padrão para contagens e índices) |
long | 64 bits | -9,22e18 a 9,22e18 | Timestamps, IDs grandes, contagens extensas |
float | 32 bits (IEEE 754) | ~1,4e-45 a ~3,4e38 (com precisão limitada) | Gráficos, sensores, cálculos aproximados |
double | 64 bits (IEEE 754) | ~4,9e-324 a ~1,8e308 (mais precisão que float) | Cálculos científicos/estatísticos aproximados |
char | 16 bits | 0 a 65.535 (UTF-16 code unit) | Caracteres, manipulação de texto em baixo nível |
Observações importantes:
charé sem sinal (não existecharnegativo).floatedoublesão aproximados: não use para dinheiro quando precisão decimal exata for necessária.- Para literais:
longusa sufixoL(ex.:10L),floatusaF(ex.:1.5F),doubleé o padrão para decimais (ex.:1.5).
Literais numéricos e legibilidade
Você pode usar _ em literais para melhorar a leitura:
int populacao = 214_000_000; // ok, mais legível
long distancia = 9_460_730_472_580L;
int binario = 0b1010_0101; // binário
int hex = 0xFF_EC_DE_5E; // hexadecimalDeclaração, inicialização e escopo de variáveis
Uma variável precisa de tipo, nome e, em muitos casos, inicialização. Variáveis locais (dentro de métodos) devem ser inicializadas antes do uso.
int idade = 30;
double altura = 1.75;
boolean ativo = true;
char inicial = 'J';Boas práticas de nomes
- Use nomes descritivos:
totalPedido,quantidadeItens,taxaJuros. - Evite abreviações ambíguas:
v,x1,tmp(a menos que o contexto seja óbvio).
Constantes com final
final indica que o valor não pode ser reatribuído após a inicialização. Em constantes, é comum usar caixa alta com underscore.
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
final int DIAS_DA_SEMANA = 7;
final double PI = 3.141592653589793;
final long TIMEOUT_MS = 5_000L;Em variáveis locais, final também ajuda a evitar reatribuições acidentais e melhora a clareza.
Inferência de tipo local com var (quando aplicável)
var permite que o compilador infira o tipo de uma variável local a partir do inicializador. Não é um tipo dinâmico: o tipo é fixado na compilação.
- Disponível para variáveis locais (dentro de métodos, blocos,
for). - Exige inicialização na mesma linha.
- Não pode ser usado para campos de classe (em Java padrão) nem para parâmetros.
var quantidade = 10; // int
var taxa = 0.15; // double
var nome = "Ana"; // String
var ativo = true; // booleanClareza: prefira var quando o tipo é óbvio pelo lado direito ou quando reduz repetição sem esconder informação importante.
// Bom: tipo evidente
var total = 0;
// Menos claro: o tipo inferido pode surpreender
var valor = 1; // int, não long
var preco = 1.0; // double, não BigDecimalConversões (casting): implícitas, explícitas e seguras
Widening (conversão implícita) — geralmente segura
Quando você atribui um tipo menor a um maior, o Java faz a conversão automaticamente (não há perda de magnitude, embora possa haver mudança de precisão ao ir para ponto flutuante).
int a = 100;
long b = a; // int -> long (ok)
double c = b; // long -> double (pode perder precisão em valores muito grandes)Ordem típica de widening numérico: byte → short → int → long → float → double. (char pode ir para int, long, etc.)
Narrowing (conversão explícita) — exige cuidado
Ao converter de um tipo maior para um menor, você precisa de cast explícito e pode ocorrer perda de dados.
long total = 3_000_000_000L;
int totalInt = (int) total; // overflow: valor final não cabe em intPasso a passo para um cast mais seguro:
- Verifique o intervalo do tipo de destino (
Integer.MIN_VALUEeInteger.MAX_VALUE, por exemplo). - Valide antes de converter.
- Se estiver fora do intervalo, trate (erro, ajuste, log, etc.).
long total = 3_000_000_000L;
if (total < Integer.MIN_VALUE || total > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Fora do intervalo de int: " + total);
}
int totalInt = (int) total;Promoção numérica em expressões (pegadinhas comuns)
Em expressões aritméticas, tipos menores que int (byte, short, char) são promovidos para int. Isso afeta atribuições e pode exigir cast.
byte x = 10;
byte y = 20;
// byte soma = x + y; // erro: x+y é int
byte soma = (byte) (x + y);Quando há mistura de tipos, o resultado tende ao tipo “mais largo” envolvido:
int i = 1;
long l = 2L;
var r1 = i + l; // long
double d = 2.5;
var r2 = l + d; // doubleOverflow e underflow: como acontecem e como detectar
Overflow ocorre quando um valor ultrapassa o máximo do tipo; underflow quando fica abaixo do mínimo (ou, em ponto flutuante, quando fica tão pequeno que vira 0.0). Em inteiros, Java não lança erro automaticamente: o valor “dá a volta” (wrap-around).
int max = Integer.MAX_VALUE;
int estourou = max + 1; // vira Integer.MIN_VALUE
int min = Integer.MIN_VALUE;
int estourou2 = min - 1; // vira Integer.MAX_VALUEOperações seguras com Math.*Exact
Para inteiros, use métodos que lançam ArithmeticException em overflow:
int a = 2_000_000_000;
int b = 2_000_000_000;
int soma = Math.addExact(a, b); // lança ArithmeticExceptionOutros úteis: Math.subtractExact, Math.multiplyExact, Math.incrementExact, Math.decrementExact, Math.toIntExact(long).
Divisão, arredondamento e precisão
Divisão inteira vs. divisão com decimais
Se ambos os operandos são inteiros, a divisão é inteira (trunca a parte decimal).
int a = 5;
int b = 2;
int divInt = a / b; // 2
double divDouble = a / (double) b; // 2.5Arredondamento com Math
Math.round: arredonda para o inteiro mais próximo (retornalongparadoubleeintparafloat).Math.floor: arredonda para baixo (retornadouble).Math.ceil: arredonda para cima (retornadouble).
double v = 10.6;
long r = Math.round(v); // 11
double f = Math.floor(v); // 10.0
double c = Math.ceil(v); // 11.0Por que double pode “errar” em decimais
Alguns valores decimais não têm representação binária exata. Isso pode aparecer em somas simples:
double x = 0.1 + 0.2;
System.out.println(x); // pode imprimir 0.30000000000000004Para comparações, evite == com ponto flutuante; use tolerância (epsilon):
double esperado = 0.3;
double obtido = 0.1 + 0.2;
double eps = 1e-9;
boolean ok = Math.abs(esperado - obtido) < eps;Validação de entrada numérica (passo a passo)
Ao ler números como texto (por exemplo, de um formulário, arquivo ou console), valide antes de converter para evitar exceções e garantir regras de negócio (faixa permitida, não-negativo, etc.).
Passo a passo: ler texto, validar e converter
- Receba a entrada como
String. - Tente converter com
Integer.parseInt,Long.parseLong,Double.parseDouble, etc. - Trate
NumberFormatException. - Valide regras (intervalo, mínimo/máximo, etc.).
String entrada = "42";
int valor;
try {
valor = Integer.parseInt(entrada);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Número inválido: " + entrada);
}
if (valor < 0 || valor > 120) {
throw new IllegalArgumentException("Idade fora do intervalo: " + valor);
}Para decimais, cuidado com separador: Double.parseDouble espera ponto (.). Se sua entrada vier com vírgula, normalize:
String entrada = "10,5";
entrada = entrada.replace(',', '.');
double valor = Double.parseDouble(entrada);Exercícios práticos (com foco em cálculos, arredondamento e validação)
1) Conversão segura de long para int
Objetivo: ler um número (como String), converter para long e depois para int apenas se couber.
- Entrada:
"3000000000"(3 bilhões) - Saída esperada: erro informando que está fora do intervalo de
int
String entrada = "3000000000";
long valor = Long.parseLong(entrada);
int convertido;
try {
convertido = Math.toIntExact(valor);
} catch (ArithmeticException e) {
throw new IllegalArgumentException("Fora do intervalo de int: " + valor);
}2) Cálculo de média com divisão correta
Objetivo: calcular a média de 3 inteiros e retornar um double com uma casa decimal.
- Valores: 7, 8, 10
- Média: 8.3
int n1 = 7, n2 = 8, n3 = 10;
double media = (n1 + n2 + n3) / 3.0;
double media1casa = Math.round(media * 10.0) / 10.0; // 1 casa
System.out.println(media1casa);3) Simulador de desconto com arredondamento
Objetivo: aplicar 12% de desconto e arredondar para 2 casas decimais (aproximação com double).
- Preço: 199.90
- Desconto: 12%
- Preço final (2 casas): 175.91
double preco = 199.90;
double desconto = 0.12;
double finalBruto = preco * (1.0 - desconto);
double final2casas = Math.round(finalBruto * 100.0) / 100.0;
System.out.println(final2casas);4) Detectando overflow em multiplicação
Objetivo: multiplicar dois int com segurança e tratar overflow.
- Valores: 50.000 e 50.000
- Resultado real: 2.500.000.000 (não cabe em
int)
int a = 50_000;
int b = 50_000;
try {
int prod = Math.multiplyExact(a, b);
System.out.println(prod);
} catch (ArithmeticException e) {
System.out.println("Overflow ao multiplicar: " + a + " * " + b);
}5) Validação de entrada numérica com faixa e fallback
Objetivo: receber uma String que deveria ser um percentual inteiro de 0 a 100. Se inválido, usar 0.
String entrada = "105"; // teste com "abc", "-1", "50"
int percentual;
try {
percentual = Integer.parseInt(entrada);
if (percentual < 0 || percentual > 100) {
percentual = 0;
}
} catch (NumberFormatException e) {
percentual = 0;
}
System.out.println(percentual);6) Promoção numérica e cast consciente
Objetivo: somar dois byte e armazenar em byte sem perder o controle do que acontece.
- Teste com valores pequenos (10 + 20) e depois com valores que estouram (120 + 120).
byte x = 120;
byte y = 120;
int somaInt = x + y; // promoção para int
System.out.println(somaInt); // 240
byte somaByte = (byte) (x + y); // overflow em byte (-16)
System.out.println(somaByte);Tarefa: implemente uma validação para impedir a conversão para byte quando somaInt estiver fora de Byte.MIN_VALUE e Byte.MAX_VALUE.