Java int, long, short e byte
Números inteiros são os mais usados em qualquer programa: quantidades, idades, contadores, códigos. O Java tem quatro tipos para eles, que diferem só no tamanho. Nesta aula você vai ver quando usar cada um, como escrever números grandes e o que acontece quando um número não cabe no tipo, o famoso overflow.
- Os tipos
int,long,shortebyte, e por que ointé o padrão. - O sufixo
Le o errointeger number too large. - Os limites
MAX_VALUEeMIN_VALUE. - O overflow: por que
Integer.MAX_VALUE + 1dá um número negativo, e como se proteger comMath.addExact. - Como escrever
1_000_000, números em binário, hexadecimal e octal.
Os quatro tipos inteiros
Pense em potes de tamanhos diferentes. Todos guardam a mesma coisa (números inteiros, positivos ou negativos, sem vírgula); o que muda é até onde cabe.
| Tipo | Bits | Menor valor | Maior valor | Use para |
|---|---|---|---|---|
byte | 8 | -128 | 127 | Dados brutos de arquivos e da rede (assunto avançado) |
short | 16 | -32.768 | 32.767 | Raramente; economizar memória em grandes volumes |
int | 32 | -2.147.483.648 | 2.147.483.647 | Quase tudo: quantidades, idades, contadores |
long | 64 | -9.223.372.036.854.775.808 | 9.223.372.036.854.775.807 | Números que podem passar de 2 bilhões |
Cada bit a mais dobra a quantidade de valores possíveis. Com 8 bits há 28 = 256 combinações: metade para os negativos (-128 a -1) e o resto para o zero e os positivos (0 a 127). Por isso o maior valor é sempre "um a menos" que o menor, sem o sinal.
int: o padrão
Todo número inteiro que você escreve no código, como 29 ou -5, é um int para o Java. É o tipo mais rápido para o processador e cabe até cerca de 2,1 bilhões, o que basta para a grande maioria das contas:
int alunos = 32; int temperaturaMinima = -3; int habitantesDoBrasil = 213000000;
Use int sempre que não houver um bom motivo para outro tipo.
long e o sufixo L
A população mundial passa de 8 bilhões, mais do que cabe num int. É trabalho para o long. Mas veja o que acontece na primeira tentativa:
public class Main {
public static void main(String[] args) {
long populacaoMundial = 3000000000;
}
}
$ javac Main.java
Main.java:3: error: integer number too large
long populacaoMundial = 3000000000;
^
1 error
"Número inteiro grande demais". Mas a variável é long! O problema não é a variável, é o número escrito: como dito acima, todo número inteiro no código é um int, e 3000000000 não cabe num int. O Java reclama antes mesmo de olhar para a variável.
A solução é dizer que o número é long, colocando um L no fim:
public class Main {
public static void main(String[] args) {
long populacaoMundial = 8100000000L;
long visitas = 25;
System.out.println(populacaoMundial);
System.out.println(visitas);
}
}
$ javac Main.java && java Main 8100000000 25
- long
- O tipo da variável: inteiro de 64 bits.
- populacaoMundial
- O nome.
- 8100000000L
- Um literal
long("literal" é um valor escrito direto no código). OLnão aparece na saída; só avisa o compilador.
Repare na segunda variável: long visitas = 25; funciona sem L, porque 25 cabe num int e o Java converte sozinho um int para long (um pote menor sempre cabe num maior; veja Conversão de Tipos). O L só é obrigatório quando o número passa de 2.147.483.647.
L maiúsculo
O Java também aceita l minúsculo (25l), mas ele parece o dígito 1: 25l lê-se facilmente como "251". Use sempre L.
Missão: a distância da Terra ao Sol é cerca de 149.600.000.000 metros. O código não compila. Corrija para que ele mostre 149600000000.
public class Main {
public static void main(String[] args) {
long distanciaAoSol = 149600000000;
System.out.println(distanciaAoSol);
}
}
public class Main {
public static void main(String[] args) {
long distanciaAoSol = 149600000000L;
System.out.println(distanciaAoSol);
}
}
short e byte
São os potes pequenos. Você pode atribuir a eles um número escrito no código desde que ele caiba; o Java confere na compilação:
public class Main {
public static void main(String[] args) {
short s = 32767;
byte b = -128;
short s2 = 40000;
}
}
$ javac Main.java
Main.java:5: error: incompatible types: possible lossy conversion from int to short
short s2 = 40000;
^
1 error
As linhas 3 e 4 passaram: 32.767 e -128 são exatamente os limites. Já 40.000 não cabe num short, e o Java avisa que guardar esse int ali seria uma "conversão com perda". Em programas do dia a dia você quase não vai usar short e byte; o byte aparece quando se lê arquivos e dados da rede, byte a byte.
Os limites: MAX_VALUE e MIN_VALUE
Cada tipo tem duas constantes na sua classe embrulho (wrapper) com o maior e o menor valor:
| Constante | Valor |
|---|---|
Byte.MIN_VALUE / Byte.MAX_VALUE | -128 / 127 |
Short.MIN_VALUE / Short.MAX_VALUE | -32768 / 32767 |
Integer.MIN_VALUE / Integer.MAX_VALUE | -2147483648 / 2147483647 |
Long.MIN_VALUE / Long.MAX_VALUE | -9223372036854775808 / 9223372036854775807 |
Repare que a classe do int se chama Integer, não Int. Esses valores foram impressos pelo JDK em Tipos Primitivos.
Overflow: quando o número "dá a volta"
O que acontece se você somar 1 ao maior int? Na escrita do código o Java confere os limites, mas durante uma conta ele não confere nada. Veja:
public class Main {
public static void main(String[] args) {
int maior = Integer.MAX_VALUE;
System.out.println(maior);
System.out.println(maior + 1);
int menor = Integer.MIN_VALUE;
System.out.println(menor - 1);
byte b = 127;
b++;
System.out.println(b);
}
}
$ javac Main.java && java Main 2147483647 -2147483648 « maior + 1 virou o MENOR int 2147483647 « menor - 1 virou o MAIOR int -128 « 127 + 1 num byte virou -128
Nenhum erro, nenhum aviso: o programa simplesmente deu a resposta errada. Isso é o overflow ("transbordamento"). Pense no hodômetro de um carro antigo, com 6 rodinhas: depois de 999.999 km, ele volta para 000.000. O int faz o mesmo, só que a "volta" leva do maior positivo ao menor negativo, por causa do jeito como os negativos são guardados em bits.
A linha b++; soma 1 a b (o ++ é explicado em Operadores Aritméticos).
Missão: veja o overflow com seus próprios olhos. No JShell, digite Integer.MAX_VALUE + 1. Depois compare com Integer.MAX_VALUE + 1L (com o L, a conta é feita em long e não transborda).
Integer.MAX_VALUE + 1
O overflow escondido: conta de int guardada em long
Este é o caso que engana até programadores experientes. A Ana quer saber quantos microssegundos há num dia e, prevenida, usa um long:
public class Main {
public static void main(String[] args) {
long microsPorDia = 24 * 60 * 60 * 1000 * 1000;
System.out.println(microsPorDia);
long certo = 24L * 60 * 60 * 1000 * 1000;
System.out.println(certo);
}
}
$ javac Main.java && java Main 500654080 « errado! 86400000000 « certo: 86,4 bilhões
Por que a primeira deu errado se a variável é long? Porque o Java faz a conta primeiro e só depois guarda. Todos os números da conta (24, 60, 1000) são int, então a conta inteira é feita em int, transborda no caminho, e o resultado já errado é guardado no long. Na segunda linha, o 24L faz a conta ser feita em long desde o começo. Essa regra ("o tipo da conta depende dos números envolvidos") se chama promoção e está em Conversão de Tipos.
Como se proteger: Math.addExact
Quando um overflow seria grave (dinheiro, estoque, contagens importantes), o Java oferece métodos que fazem a conta e conferem: Math.addExact (somar), Math.subtractExact (subtrair), Math.multiplyExact (multiplicar). Se o resultado não couber, em vez de dar a volta eles param o programa com um erro:
public class Main {
public static void main(String[] args) {
int saldo = 2_000_000_000;
int deposito = 500_000_000;
System.out.println(saldo + deposito);
int total = Math.addExact(saldo, deposito);
System.out.println(total);
}
}
$ javac Main.java && java Main -1794967296 Exception in thread "main" java.lang.ArithmeticException: integer overflow at java.base/java.lang.Math.addExact(Math.java:915) at Main.main(Main.java:6)
- Math.addExact
- Método da classe Math que soma dois números com conferência de overflow (exact = "exato").
- (saldo, deposito)
- Os dois números a somar, separados por vírgula.
A linha 5 mostrou o saldo "negativo" sem reclamar. A linha 6 parou o programa com uma exceção: ArithmeticException: integer overflow ("exceção aritmética: overflow de inteiro"). As linhas que começam com at mostram onde aconteceu: dentro de Math.addExact, chamado na linha 6 do Main.java. O println(total) nunca rodou. Parar com erro parece pior, mas é muito melhor do que seguir com um saldo errado. Exceções têm um capítulo inteiro, começando em O que são Exceções.
| Situação | O que fazer |
|---|---|
| Os números nunca chegam perto de 2 bilhões | int e contas normais. |
| Podem passar de 2 bilhões | long (e L em pelo menos um número da conta). |
| Passar do limite seria um erro grave | Math.addExact, Math.multiplyExact… |
| Números sem limite (criptografia, fatorial de 100) | BigInteger, irmão do BigDecimal. |
Escrevendo números: sublinhado e outras bases
O sublinhado: 1_000_000
Quantos zeros tem 1000000000? Difícil de contar. Desde o Java 7 você pode separar os dígitos com _ (sublinhado), como faria com os pontos em 1.000.000.000. O Java ignora os sublinhados:
public class Main {
public static void main(String[] args) {
int milhao = 1_000_000;
long cartao = 1234_5678_9012_3456L;
int binario = 0b1010;
int hexa = 0xFF;
int octal = 010;
System.out.println(milhao);
System.out.println(cartao);
System.out.println(binario);
System.out.println(hexa);
System.out.println(octal);
System.out.println(Integer.toBinaryString(10));
System.out.println(Integer.toHexString(255));
}
}
$ javac Main.java && java Main 1000000 1234567890123456 10 255 8 « 010 NÃO é dez! 1010 ff
O sublinhado só serve para os seus olhos; na saída ele não aparece. Pode ficar entre dígitos, mas não no começo nem no fim do número, nem colado no L.
Outras bases
Normalmente escrevemos números na base 10 (dígitos de 0 a 9). O Java aceita outras três, indicadas por um prefixo:
| Prefixo | Base | Dígitos | Exemplo | Vale | Onde aparece |
|---|---|---|---|---|---|
| (nenhum) | 10, decimal | 0–9 | 255 | 255 | Sempre |
0b | 2, binário | 0 e 1 | 0b1010 | 10 | Bits, permissões, sinais de hardware |
0x | 16, hexadecimal | 0–9 e A–F | 0xFF | 255 | Cores (0xFF8800), endereços de memória |
0 | 8, octal | 0–7 | 010 | 8 | Quase nunca (permissões de arquivo no Linux) |
Integer.toBinaryString(10) e Integer.toHexString(255) fazem o caminho inverso: mostram um número em binário e em hexadecimal.
Um zero no começo transforma o número em octal: int codigo = 010; guarda oito, não dez. E se aparecer um 8 ou 9 depois do zero, nem compila (veja "illegal digit in an octal literal" abaixo). Nunca escreva zeros à esquerda em números; se o zero importa (CEP, código de produto), o dado é texto: String cep = "09010-000";.
Divisão de inteiros: sem casas decimais
Uma última característica que pega todo iniciante: quando os dois números são inteiros, a divisão também dá um inteiro, e a parte decimal é descartada (não arredondada). 7 / 2 dá 3, e -7 / 2 dá -3. O resto da divisão é obtido com %: 7 % 2 dá 1. Esse assunto tem explicação completa, com exemplos, em Operadores Aritméticos.
Quando dá errado
$ javac Main.java
Main.java:3: error: integer number too large
long populacaoMundial = 3000000000;
^
1 error
O que quer dizer: o número escrito no código passa de 2.147.483.647, o limite de um literal int. Acontece mesmo que a variável seja long.
Como consertar: coloque L no fim: 3000000000L. Se a variável for int, troque também o tipo para long.
public class Main {
public static void main(String[] args) {
long a = 10;
int b = a;
}
}
$ javac Main.java
Main.java:4: error: incompatible types: possible lossy conversion from long to int
int b = a;
^
1 error
O que quer dizer: o pote maior (long) não cabe automaticamente no menor (int). O Java não olha o valor guardado (10 caberia); olha só os tipos.
Como consertar: se você tem certeza de que o valor cabe, peça a conversão explicitamente: int b = (int) a;. Isso é o casting, explicado em Conversão de Tipos.
public class Main {
public static void main(String[] args) {
int cep = 09;
}
}
$ javac Main.java
Main.java:3: error: illegal digit in an octal literal
int cep = 09;
^
1 error
O que quer dizer: "dígito ilegal num literal octal". O zero à esquerda fez o Java ler o número em base 8, que não tem o dígito 9.
Como consertar: tire o zero (9) ou, se o zero faz parte do dado, use String.
$ javac Main.java
Main.java:3: error: illegal underscore
int x = 100_;
^
1 error
O que quer dizer: o sublinhado está num lugar proibido: no fim do número. Também é proibido antes do L (100_L) e logo depois de 0x ou 0b. No começo (_100) o erro é outro: o Java acha que é o nome de uma variável e responde cannot find symbol.
Como consertar: sublinhados só entre dígitos: 1_000.
$ javac Main.java && java Main -1794967296
O que aconteceu: overflow. Uma conta passou do limite do tipo e "deu a volta". O javac e o java não avisam.
Como consertar: use long (com L nos números da conta, como 24L * 60) ou Math.addExact/Math.multiplyExact, que lançam ArithmeticException: integer overflow em vez de errar em silêncio.
Missão: o estoque da loja da Ana tem 50.000 caixas com 50.000 parafusos cada. A conta transborda e mostra um número sem sentido. Troque a multiplicação por Math.multiplyExact(caixas, porCaixa) para que o programa pare com ArithmeticException em vez de mostrar o valor errado.
public class Main {
public static void main(String[] args) {
int caixas = 50_000;
int porCaixa = 50_000;
int parafusos = caixas * porCaixa;
System.out.println("Parafusos: " + parafusos);
}
}
public class Main {
public static void main(String[] args) {
int caixas = 50_000;
int porCaixa = 50_000;
int parafusos = Math.multiplyExact(caixas, porCaixa);
System.out.println("Parafusos: " + parafusos);
}
}
Referência
| Escrita | O que é | Exemplo |
|---|---|---|
123 | Literal int (decimal) | int n = 123; |
123L | Literal long | long n = 8100000000L; |
1_000_000 | Sublinhado para separar dígitos | int milhao = 1_000_000; |
0b1010 | Binário (10) | int flags = 0b1010; |
0xFF | Hexadecimal (255) | int cor = 0xFF8800; |
010 | Octal (8) — evite | |
Integer.MAX_VALUE | Maior int: 2147483647 | Também Long.MAX_VALUE, Short.MAX_VALUE, Byte.MAX_VALUE |
Integer.MIN_VALUE | Menor int: -2147483648 | |
Math.addExact(a, b) | Soma com conferência de overflow | Também subtractExact, multiplyExact |
Integer.toBinaryString(n) | Texto com n em binário | "1010" |
Integer.toHexString(n) | Texto com n em hexadecimal | "ff" |
Exercícios
1. O sufixo
Complete para o código compilar:
2. O maior int
Complete com a constante que guarda o maior int:
3. Um milhão legível
Escreva o número um milhão usando sublinhados para separar os milhares:
4. O que System.out.println(Integer.MAX_VALUE + 1); mostra?
5. Quanto vale int x = 010;?
6. Por que long x = 24 * 60 * 60 * 1000 * 1000; guarda um valor errado?
Resumo
- Quatro inteiros, do menor ao maior:
byte(8 bits),short(16),int(32) elong(64). Useintpor padrão elongacima de 2 bilhões. - Todo número inteiro escrito no código é
int; acima de 2.147.483.647, escrevaLno fim, senão:integer number too large. Integer.MAX_VALUE,Integer.MIN_VALUEe companhia guardam os limites.- Overflow: passar do limite numa conta não dá erro; o número "dá a volta" (
MAX_VALUE + 1viraMIN_VALUE). Math.addExact/multiplyExactlançamArithmeticException: integer overflowem vez de errar em silêncio.1_000_000é só mais legível.0b= binário,0x= hexadecimal,0à esquerda = octal (cuidado!).- Divisão de inteiros descarta a parte decimal:
7 / 2é3.