Java Tipos Primitivos

Na aula Variáveis você viu que toda variável tem um tipo, o "formato da caixa". O Java tem exatamente oito tipos básicos, embutidos na linguagem, chamados tipos primitivos. Esta aula apresenta os oito de uma vez, para você ter o mapa completo; as próximas aulas aprofundam cada grupo.

Você vai aprender
  • Os 8 tipos primitivos: o que cada um guarda, quanto espaço ocupa e até onde vai.
  • Por que o Java exige tipos (e como eles protegem você de erros).
  • A diferença entre um tipo primitivo e um tipo de referência, como String.
  • Qual tipo escolher em cada situação.

Por que existem tipos?

Imagine o armário de uma cozinha. Há potes pequenos para o sal, potes grandes para o arroz, uma garrafa para o óleo. Você não guarda óleo num saquinho de papel nem uma colher de sal num pote de 5 kg. Cada recipiente é feito para um tipo de conteúdo e um tamanho.

No computador é igual. Tudo é guardado na memória como bits (zeros e uns), e o mesmo punhado de bits pode significar um número, uma letra ou "verdadeiro". O tipo diz ao Java como ler aqueles bits e quanto espaço reservar. Em troca, o Java confere, antes de rodar, se você está guardando cada coisa no recipiente certo:

public class Main {
    public static void main(String[] args) {
        int quantidade = 2.5;
    }
}
$ javac Main.java
Main.java:3: error: incompatible types: possible lossy conversion from double to int
        int quantidade = 2.5;
                         ^
1 error

"Tipos incompatíveis: possível conversão com perda, de double para int". Uma caixa int só guarda inteiros; para caber, o 2.5 perderia o .5, e o Java não faz isso escondido. O erro aparece na compilação, antes de o programa rodar, e é exatamente para isso que os tipos existem: achar erros cedo. Linguagens que verificam os tipos assim são chamadas de estaticamente tipadas.


Os 8 tipos primitivos

Eles se dividem em quatro famílias:

FamíliaTiposGuardamAula
Inteirosbyte, short, int, longNúmeros sem parte decimalint, long, short, byte
Decimais (ponto flutuante)float, doubleNúmeros com parte decimaldouble e float
CaracterecharUma letra, dígito ou símbolochar e boolean
Lógicobooleantrue (verdadeiro) ou false (falso)char e boolean

E aqui está a tabela completa. Não precisa decorar os números: guarde a ideia de que cada tipo tem um limite.

TipoTamanhoFaixa de valoresValor padrãoExemplo
byte8 bits (1 byte)-128 a 1270byte idadeDoGato = 7;
short16 bits (2 bytes)-32.768 a 32.7670short ano = 1997;
int32 bits (4 bytes)-2.147.483.648 a 2.147.483.647 (cerca de ±2,1 bilhões)0int habitantes = 213000000;
long64 bits (8 bytes)cerca de ±9,2 quintilhões (19 dígitos)0Llong estrelas = 400000000000L;
float32 bits (4 bytes)até cerca de ±3,4 × 1038, com 6 a 7 dígitos de precisão0.0ffloat temperatura = 36.5f;
double64 bits (8 bytes)até cerca de ±1,8 × 10308, com 15 a 16 dígitos de precisão0.0double preco = 9.90;
char16 bits (2 bytes)um caractere Unicode (códigos 0 a 65.535)'\u0000'char inicial = 'A';
booleannão definido pela especificaçãotrue ou falsefalseboolean temCadastro = true;

Os nomes vêm do inglês: byte (8 bits), short ("curto"), int (integer, "inteiro"), long ("longo"), float ("flutuar", de floating point, "ponto flutuante"), double ("duplo": o dobro da precisão do float), char (character, "caractere") e boolean (do matemático George Boole, que criou a lógica de verdadeiro e falso).

Os oito num programa

public class Main {
    public static void main(String[] args) {
        byte idadeDoGato = 7;
        short anoDeNascimento = 1997;
        int habitantes = 213000000;
        long estrelas = 400000000000L;
        float temperatura = 36.5f;
        double preco = 9.90;
        char inicial = 'A';
        boolean temCadastro = true;
        System.out.println(idadeDoGato);
        System.out.println(anoDeNascimento);
        System.out.println(habitantes);
        System.out.println(estrelas);
        System.out.println(temperatura);
        System.out.println(preco);
        System.out.println(inicial);
        System.out.println(temCadastro);
    }
}
$ javac Main.java && java Main
7
1997
213000000
400000000000
36.5
9.9                « o zero do fim de 9.90 não é guardado
A
true

Repare nos detalhes de escrita, cada um explicado na aula da sua família:

400000000000L
O L no fim marca um número long. Sem ele, o Java acha que é um int grande demais e recusa (int, long, short, byte).
36.5f
O f marca um float. Sem ele, 36.5 é double (double e float).
'A'
Um char vai entre aspas simples; texto (String) vai entre aspas duplas (char e boolean).
true
Um boolean é escrito sem aspas, em minúsculas.

Brinque com o código: mude os valores. Tente byte idadeDoGato = 200; (passa do limite de 127), tire o L do long ou o f do float, e veja o que o compilador responde.

public class Main {
    public static void main(String[] args) {
        byte idadeDoGato = 7;
        short anoDeNascimento = 1997;
        int habitantes = 213000000;
        long estrelas = 400000000000L;
        float temperatura = 36.5f;
        double preco = 9.90;
        char inicial = 'A';
        boolean temCadastro = true;
        System.out.println(idadeDoGato);
        System.out.println(anoDeNascimento);
        System.out.println(habitantes);
        System.out.println(estrelas);
        System.out.println(temperatura);
        System.out.println(preco);
        System.out.println(inicial);
        System.out.println(temCadastro);
    }
}

Os limites, direto do Java

Você não precisa decorar as faixas: o próprio Java as guarda em constantes, como Integer.MAX_VALUE ("valor máximo de um inteiro"). Byte, Short, Integer, Long, Float, Double e Character são classes "irmãs" dos primitivos, chamadas wrappers:

public class Main {
    public static void main(String[] args) {
        System.out.println("byte:  " + Byte.MIN_VALUE + " a " + Byte.MAX_VALUE);
        System.out.println("short: " + Short.MIN_VALUE + " a " + Short.MAX_VALUE);
        System.out.println("int:   " + Integer.MIN_VALUE + " a " + Integer.MAX_VALUE);
        System.out.println("long:  " + Long.MIN_VALUE + " a " + Long.MAX_VALUE);
        System.out.println("float:  até " + Float.MAX_VALUE);
        System.out.println("double: até " + Double.MAX_VALUE);
        System.out.println("char:  " + (int) Character.MIN_VALUE + " a " + (int) Character.MAX_VALUE);
        System.out.println("bits de um int: " + Integer.SIZE + ", bytes: " + Integer.BYTES);
    }
}
$ javac Main.java && java Main
byte:  -128 a 127
short: -32768 a 32767
int:   -2147483648 a 2147483647
long:  -9223372036854775808 a 9223372036854775807
float:  até 3.4028235E38
double: até 1.7976931348623157E308
char:  0 a 65535
bits de um int: 32, bytes: 4

3.4028235E38 é a notação científica que o Java usa para números enormes: quer dizer 3,4028235 × 1038 (explicada em double e float). O (int) antes de Character.MIN_VALUE pede para mostrar o código numérico em vez do caractere; isso se chama casting (Conversão de Tipos).

Missão: no JShell, descubra o maior valor que cabe num int. Digite Integer.MAX_VALUE e aperte Enter. Depois, por curiosidade, experimente Long.MAX_VALUE e Byte.MIN_VALUE.

Integer.MAX_VALUE

O valor padrão

A coluna "valor padrão" da tabela é o valor que o Java coloca sozinho em variáveis que ficam dentro de objetos e arrays (os atributos e os elementos de um array, assuntos de outras aulas). O JShell, que guarda as variáveis de um jeito parecido, mostra esses valores quando você declara sem atribuir:

$ jshell
|  Welcome to JShell -- Version 25.0.4.1
|  For an introduction type: /help intro

jshell> int x;
x ==> 0

jshell> double d;
d ==> 0.0

jshell> boolean b;
b ==> false

jshell> char c;
c ==> '\000'

jshell> String s;
s ==> null

jshell> /exit
|  Goodbye

'\000' é o caractere de código zero (invisível). null quer dizer "nenhum objeto"; você vai entender na próxima seção.

Variáveis dentro do main não ganham valor padrão

Num programa, as variáveis declaradas dentro de um método (como o main) são variáveis locais e começam sem valor nenhum. Usar uma delas antes de atribuir dá variable … might not have been initialized, como você viu em Variáveis. O valor padrão vale só para atributos e arrays (e para o JShell).


Primitivo × referência: e a String?

Você já usou String e ela não está na lista dos oito. Isso porque String não é primitivo: é uma classe, e as variáveis de classes são de tipo de referência.

Tipo primitivoTipo de referência
Quais sãoSó os 8: byte short int long float double char booleanTodos os outros: String, Scanner, arrays, as classes que você criar…
Como se escreveTudo minúsculo: intPor convenção, começa com maiúscula: String
O que a variável guardaO próprio valor (29)O endereço de um objeto que mora em outro lugar da memória
Tem métodos (ações com ponto)?NãoSim: nome.length(), nome.toUpperCase()
Pode valer null?NãoSim (null = "não aponta para nenhum objeto")

Na comparação da caixa: uma variável primitiva é uma caixa com o valor dentro. Uma variável de referência é uma caixa com um papel anotado com o endereço de onde o objeto está guardado. O objeto String sabe fazer coisas, como contar as próprias letras; um int é só um número.

public class Main {
    public static void main(String[] args) {
        String nome = "Ana";
        int idade = 29;
        System.out.println(nome.length());
        System.out.println(nome.toUpperCase());
        System.out.println(idade.length());
    }
}
$ javac Main.java
Main.java:7: error: int cannot be dereferenced
        System.out.println(idade.length());
                                ^
1 error

"int não pode ser desreferenciado": o ponto (.) depois de uma variável quer dizer "vá até o objeto e peça algo a ele". Um int não aponta para objeto nenhum, então não há onde ir. Sem a linha 7, o programa compila e mostra 3 (o número de letras) e ANA. Strings ganham aulas próprias: Strings e Métodos de String. A diferença entre guardar o valor e guardar o endereço volta em Classes e Objetos.

Cada primitivo tem uma classe "embrulho"

int tem Integer, double tem Double, char tem Character, boolean tem Boolean, e assim por diante. São elas que guardam as constantes como Integer.MAX_VALUE e métodos úteis como Integer.parseInt. Veja Wrappers e Autoboxing.


Como escolher o tipo

Na prática, quatro tipos resolvem quase tudo. Comece por esta tabela:

Você quer guardar…UseExemplo
Quantidades, contagens, idades, anosintint alunos = 32;
Números inteiros que podem passar de 2 bilhões (população mundial, milissegundos, tamanho de arquivos)longlong populacao = 8100000000L;
Medidas e contas com vírgula (altura, média, temperatura)doubledouble media = 7.5;
Sim ou não, ligado ou desligadobooleanboolean aprovada = true;
Uma única letra ou símbolocharchar turma = 'B';
Texto (nome, frase, até uma letra só, se for "texto")String (referência)String nome = "Ana";
DinheiroBigDecimal (referência)Veja BigDecimal e Dinheiro
Economizar memória em milhões de valores pequenosbyte, short, floatRaro em programas do dia a dia
Por que não usar byte para uma idade, já que cabe?

Poderia, mas não vale a pena. As contas em Java são feitas em int (você vai ver em Conversão de Tipos que byte + byte dá int), então um byte obriga a conversões chatas, e a economia de 3 bytes não faz diferença num programa comum. Use int como padrão para inteiros e double para decimais.

Número de telefone, CPF e CEP não são números

Você não faz contas com eles, eles podem começar com zero (01310-100) e o CPF passa do limite do int. Guarde em String: String cep = "01310-100";.


Quando dá errado

"cannot find symbol … symbol: class string"
public class Main {
    public static void main(String[] args) {
        string nome = "Ana";
    }
}
$ javac Main.java
Main.java:3: error: cannot find symbol
        string nome = "Ana";
        ^
  symbol:   class string
  location: class Main
1 error

O que quer dizer: o Java procurou uma classe chamada string (minúsculo) e não achou. A classe se chama String, com S maiúsculo. O erro inverso também existe: Int idade = 29; dá symbol: class Int, porque os primitivos são sempre minúsculos.

Como consertar: primitivos em minúsculas (int, double, boolean); String com maiúscula.

"possible lossy conversion from int to byte"
$ javac Main.java
Main.java:3: error: incompatible types: possible lossy conversion from int to byte
        byte idade = 200;
                     ^
1 error

O que quer dizer: 200 passa do limite do byte (127). O Java trata o 200 como um int e avisa que guardá-lo num byte perderia informação. Com byte idade = 100; não há erro: o Java vê que 100 cabe.

Como consertar: use um tipo maior (int). Os limites e o que acontece quando um número passa deles estão em int, long, short, byte.

"int cannot be dereferenced"

O que quer dizer: você colocou um ponto depois de uma variável primitiva (idade.length(), preco.toString()). Primitivos não têm métodos.

Como consertar: use os métodos das classes embrulho, que recebem o valor entre parênteses: String.valueOf(idade) ou Integer.toString(idade) transformam o número em texto (Conversão de Tipos).

Missão: a professora Ana declarou tudo como int e o programa não compila. Troque o tipo de cada variável pelo tipo certo (e, se precisar, as aspas do valor) para a saída ser 32 7.5 B true.

public class Main {
    public static void main(String[] args) {
        int alunos = 32;
        int media = 7.5;
        int turma = "B";
        int aprovada = true;
        System.out.println(alunos + " " + media + " " + turma + " " + aprovada);
    }
}
public class Main {
    public static void main(String[] args) {
        int alunos = 32;
        double media = 7.5;
        char turma = 'B';
        boolean aprovada = true;
        System.out.println(alunos + " " + media + " " + turma + " " + aprovada);
    }
}

Referência

TipoLiteral (como escrever o valor)Máximo / mínimoClasse embrulho
byte7Byte.MAX_VALUE / Byte.MIN_VALUEByte
short1997Short.MAX_VALUE / Short.MIN_VALUEShort
int29, 1_000_000Integer.MAX_VALUE / Integer.MIN_VALUEInteger
long29LLong.MAX_VALUE / Long.MIN_VALUELong
float36.5fFloat.MAX_VALUEFloat
double9.90, 1.5e3Double.MAX_VALUEDouble
char'A', 'é'Character.MAX_VALUECharacter
booleantrue, false—Boolean

Exercícios

1. O tipo da média

Complete com o tipo mais indicado para guardar a média 8.25:

media = 8.25;

2. Sim ou não

Complete com o tipo primitivo que guarda true ou false:

pago = false;

3. Quantos tipos?

Quantos tipos primitivos o Java tem? Escreva o número:

4. Qual destes não é um tipo primitivo?

5. Qual o melhor tipo para guardar um CEP como 01310-100?

6. O que acontece com byte nota = 300;?

7. Por que idade.length() não compila quando idade é int?


Resumo

  • O Java tem 8 tipos primitivos: byte, short, int, long (inteiros), float, double (decimais), char (um caractere) e boolean (verdadeiro/falso).
  • Cada tipo tem tamanho e faixa fixos; as constantes Integer.MAX_VALUE e companhia mostram os limites.
  • Os tipos deixam o javac achar erros antes de o programa rodar (incompatible types).
  • String não é primitivo: é uma classe (tipo de referência), começa com maiúscula, tem métodos e pode ser null.
  • Valor padrão (0, false, null…) só vale para atributos e arrays; variáveis locais precisam de valor antes do uso.
  • No dia a dia: int, long para números muito grandes, double, boolean, char e String.