Java Conversão de Tipos
Você já viu que cada variável tem um tipo fixo. Mas os programas vivem trocando valores de um tipo para outro: uma soma de inteiros que precisa virar média decimal, uma idade digitada como texto que precisa virar número, um número que precisa virar texto para aparecer numa mensagem. Esta aula reúne todas essas conversões: as que o Java faz sozinho, as que você pede com um casting e as que exigem um método.
- A conversão automática (alargamento): quando o Java converte sem você pedir.
- O casting (estreitamento): como pedir uma conversão que pode perder informação, e o que se perde.
- Como transformar número em texto e texto em número (
Integer.parseInt,String.valueOf). - Como converter entre
chareint. - A promoção em contas: por que
byte + bytedáint.
A ideia: potes de tamanhos diferentes
Volte à imagem dos potes de Tipos Primitivos. Despejar o conteúdo de um pote pequeno num pote grande é sempre seguro: cabe tudo. Despejar um pote grande num pequeno pode transbordar. O Java segue exatamente essa lógica:
| Direção | Nome técnico | Quem faz | Risco |
|---|---|---|---|
Do menor para o maior (int → double) | Alargamento (widening) | O Java, sozinho | Nenhum (quase: veja float adiante) |
Do maior para o menor (double → int) | Estreitamento (narrowing) | Você, com um casting | Perder a parte decimal ou "dar a volta" |
Entre texto e número ("42" ↔ 42) | Conversão por método | Você, chamando um método | O texto pode não ser um número |
1. Conversão automática (alargamento)
Quando o valor vai para um tipo maior, o Java converte sem você escrever nada:
public class Main {
public static void main(String[] args) {
int alunos = 32;
long grande = alunos;
double media = alunos;
float f = alunos;
char letra = 'A';
int codigo = letra;
System.out.println(grande);
System.out.println(media);
System.out.println(f);
System.out.println(codigo);
}
}
$ javac Main.java && java Main 32 32.0 « o int virou double 32.0 65 « o char virou o seu código Unicode
O caminho do alargamento segue esta ordem; qualquer tipo pode ir automaticamente para qualquer um à sua direita:
byte → short → int → long → float → double
↑
char
| De | Vai sozinho para |
|---|---|
byte | short, int, long, float, double |
short | int, long, float, double |
char | int, long, float, double |
int | long, float, double |
long | float, double |
float | double |
boolean | nenhum (não converte para nada, nem de nada) |
Repare que char e short não convertem automaticamente um no outro: char não tem negativos e short não chega a 65.535, então nenhum "cabe" inteiro no outro.
float e double
long → float é automático, mas o float só guarda 6 a 7 dígitos exatos. O valor cabe (a faixa é enorme), mas os dígitos finais se perdem:
$ javac Main.java && java Main 123456789123456789 « o long original 1.2345679E17 « no float: só 8 dígitos sobreviveram 1.2345678912345678E17 « no double: 17 dígitos, ainda falta o último 9 1.2345679E8 « até um int (123456789) perde dígitos num float
Para números inteiros grandes, fique em long. Veja double e float.
2. Casting: conversão com perda (estreitamento)
Do maior para o menor, o Java não converte sozinho. Ele recusa com um erro que você já conhece:
public class Main {
public static void main(String[] args) {
double preco = 9.99;
int inteiro = preco;
}
}
$ javac Main.java
Main.java:4: error: incompatible types: possible lossy conversion from double to int
int inteiro = preco;
^
1 error
Se você sabe o que está fazendo e aceita a perda, pode forçar a conversão escrevendo o tipo de destino entre parênteses antes do valor. Isso se chama casting (do inglês cast, "moldar", como derramar metal num molde):
- int inteiro =
- A variável de destino, do tipo menor.
- (int)
- O operador de casting: "converta o que vem a seguir para
int; eu assumo o risco". - preco;
- O valor a converter.
public class Main {
public static void main(String[] args) {
double preco = 9.99;
int inteiro = (int) preco;
System.out.println(inteiro);
System.out.println((int) -9.99);
System.out.println(Math.round(9.99));
System.out.println((int) Math.round(9.49));
System.out.println((byte) 200);
System.out.println((short) 70000);
System.out.println((int) 3.0e10);
System.out.println((long) 3.0e10);
System.out.println((int) 'A');
System.out.println((char) 66);
System.out.println((double) 7 / 2);
System.out.println((double) (7 / 2));
}
}
$ javac Main.java && java Main 9 « (int) 9.99: a parte decimal foi CORTADA, não arredondada -9 « com negativos também corta: -9.99 vira -9 10 « Math.round arredonda de verdade 9 -56 « (byte) 200: 200 não cabe num byte e "deu a volta" 4464 « (short) 70000: também deu a volta 2147483647 « (int) 30 bilhões: decimal grande demais vira o MAX_VALUE 30000000000 « num long, cabe 65 B 3.5 « (double) 7 / 2: converte o 7, depois divide 3.0 « (double) (7 / 2): divide (dá 3), depois converte
Vamos por partes, porque cada linha ensina uma regra:
| Casting | Resultado | Regra |
|---|---|---|
(int) 9.99 | 9 | De decimal para inteiro, a parte decimal é descartada (truncada). Nunca arredonda. |
(int) -9.99 | -9 | O corte vai sempre "em direção ao zero". |
Math.round(9.99) | 10 | Para arredondar, use Math.round. Ele devolve um long; se precisar de int, faça o casting do resultado: (int) Math.round(x). Veja Math. |
(byte) 200 | -56 | Entre inteiros, o valor que não cabe "dá a volta", como no overflow: 200 − 256 = −56. |
(int) 3.0e10 | 2147483647 | De decimal para inteiro, valores grandes demais param no limite do tipo (Integer.MAX_VALUE). |
(double) 7 / 2 | 3.5 | O casting vale só para o valor logo à direita (o 7). Com um double na conta, a divisão é decimal. |
(double) (7 / 2) | 3.0 | Os parênteses fazem a divisão inteira acontecer antes: 7 / 2 dá 3, e só então vira 3.0. Tarde demais. |
(int) preco cria um novo valor do tipo int; a variável preco continua sendo double e continua valendo 9.99. O tipo de uma variável nunca muda.
Missão: a soma das notas é 15 e são 2 provas, ambas em variáveis int. O programa mostra Média: 7.0. Use um casting (double) no lugar certo para ele mostrar Média: 7.5.
public class Main {
public static void main(String[] args) {
int soma = 15;
int provas = 2;
double media = soma / provas;
System.out.println("Média: " + media);
}
}
public class Main {
public static void main(String[] args) {
int soma = 15;
int provas = 2;
double media = (double) soma / provas;
System.out.println("Média: " + media);
}
}
3. Número ↔ texto
String não é um tipo primitivo, e o casting não converte entre texto e número: (int) "42" não compila. Para isso existem métodos.
Número → texto
Há três formas, e todas dão o mesmo resultado:
int idade = 29; String a = "" + idade; // concatenar com um texto vazio String b = String.valueOf(idade); // "valor de": funciona com qualquer tipo String c = Integer.toString(idade); // método da classe Integer
| Forma | Quando usar |
|---|---|
"" + idade | Rápido e comum, mas parece "truque". Normal quando o número já vai ser colado num texto: "Idade: " + idade (Concatenação). |
String.valueOf(idade) | A mais clara. Funciona com int, double, char, boolean… |
Integer.toString(idade) | Equivalente; existe também Double.toString, Long.toString… |
Texto → número: Integer.parseInt
Isso acontece o tempo todo: tudo o que o usuário digita chega como texto, e os argumentos da linha de comando também (Argumentos da Linha de Comando). Para transformar "42" no número 42, use Integer.parseInt (parse = "analisar, interpretar"):
public class Main {
public static void main(String[] args) {
int idade = 29;
String a = "" + idade;
String b = String.valueOf(idade);
String c = Integer.toString(idade);
String d = String.valueOf(1.65);
System.out.println(a + b + c);
System.out.println(d);
String texto = "42";
int numero = Integer.parseInt(texto);
System.out.println(numero + 1);
System.out.println(texto + 1);
double altura = Double.parseDouble("1.65");
System.out.println(altura * 2);
long l = Long.parseLong("8100000000");
System.out.println(l);
boolean ok = Boolean.parseBoolean("true");
System.out.println(ok);
}
}
$ javac Main.java && java Main 292929 « três textos "29" colados 1.65 43 « numero + 1: conta de verdade 421 « texto + 1: "42" colado com "1" 3.3 8100000000 true
Compare as linhas 3 e 4 da saída: com o número, + 1 soma; com o texto, + 1 cola. É a prova de que parseInt mudou o tipo.
| Texto para… | Método | Exemplo |
|---|---|---|
int | Integer.parseInt(texto) | Integer.parseInt("42") → 42 |
long | Long.parseLong(texto) | Long.parseLong("8100000000") |
double | Double.parseDouble(texto) | Double.parseDouble("1.65") → 1.65 |
boolean | Boolean.parseBoolean(texto) | "true" → true; qualquer outro texto → false |
Quando o texto não é um número: NumberFormatException
O compilador não tem como saber o que vai estar dentro de uma String. Se o texto não for um número válido, o erro aparece só na execução:
public class Main {
public static void main(String[] args) {
String quantidade = "doze";
int n = Integer.parseInt(quantidade);
System.out.println(n);
}
}
$ javac Main.java && java Main Exception in thread "main" java.lang.NumberFormatException: For input string: "doze" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) at java.base/java.lang.Integer.parseInt(Integer.java:565) at java.base/java.lang.Integer.parseInt(Integer.java:662) at Main.main(Main.java:4)
O programa compilou, começou a rodar e parou na linha 4 com uma exceção: NumberFormatException ("exceção de formato de número"), seguida do texto que causou o problema: For input string: "doze" ("para o texto de entrada "doze""). As linhas at mostram o caminho: o erro nasceu lá dentro de Integer.parseInt, chamado pela linha 4 do Main.java (a última linha at é a que interessa: a sua). O println nunca rodou.
O parseInt é exigente. Veja o que ele aceita e o que recusa (todas as recusas dão a mesma exceção, com o texto entre aspas):
| Texto | Integer.parseInt |
|---|---|
"42", "-15", "+15" | Aceita: 42, -15, 15 |
"doze" | NumberFormatException: For input string: "doze" |
"3.5" | NumberFormatException: For input string: "3.5" (não é inteiro; use Double.parseDouble) |
" 15" (com espaço) | NumberFormatException: For input string: " 15" (limpe antes com texto.strip(), de Métodos de String) |
"" (vazio) | NumberFormatException: For input string: "" |
"3000000000" | Recusa: não cabe num int (use Long.parseLong) |
Para o programa não parar, você pode "capturar" a exceção e mostrar uma mensagem amigável; isso é assunto de try e catch.
Missão: a idade chegou como texto e o programa mostra Ano que vem: 291. Converta idadeTexto para int com Integer.parseInt antes de somar, para mostrar Ano que vem: 30. Depois, por curiosidade, troque "29" por "vinte" e rode de novo.
public class Main {
public static void main(String[] args) {
String idadeTexto = "29";
System.out.println("Ano que vem: " + idadeTexto + 1);
}
}
public class Main {
public static void main(String[] args) {
String idadeTexto = "29";
int idade = Integer.parseInt(idadeTexto);
System.out.println("Ano que vem: " + (idade + 1));
}
}
4. char ↔ int
Como você viu em char e boolean, um char é um código numérico. Isso cria uma armadilha: converter o caractere '7' em int dá o código dele (55), não o número 7.
public class Main {
public static void main(String[] args) {
char digito = '7';
int valor = digito - '0';
int valor2 = Character.getNumericValue(digito);
int errado = digito;
System.out.println(valor);
System.out.println(valor2);
System.out.println(errado);
int n = 4;
char c = (char) ('0' + n);
System.out.println(c);
String s = "Ana";
char primeira = s.charAt(0);
System.out.println(primeira);
String deChar = String.valueOf('Z');
System.out.println(deChar);
}
}
$ javac Main.java && java Main
7 « '7' - '0'
7 « Character.getNumericValue('7')
55 « int errado = '7': o código Unicode!
4 « (char) ('0' + 4): número para dígito
A « primeiro caractere da String
Z « char para String
| Quero | Use | Exemplo → resultado |
|---|---|---|
Código Unicode de um char | (int) c (ou só atribuir a um int) | (int) 'A' → 65 |
char de um código | (char) n | (char) 66 → B |
Dígito '7' → número 7 | c - '0' ou Character.getNumericValue(c) | 7 |
Número 4 → dígito '4' | (char) ('0' + n) | '4' |
char → String | String.valueOf(c) | "Z" |
String → char | texto.charAt(posição) (começa em 0) | "Ana".charAt(0) → 'A' |
5. Promoção em expressões: byte + byte = int
Até aqui, as conversões aconteceram ao guardar um valor. Mas elas também acontecem no meio das contas. Antes de calcular, o Java "promove" os valores segundo duas regras:
byte,shortecharviramintantes de qualquer conta. O processador trabalha com no mínimo 32 bits.- Se os dois lados têm tipos diferentes, o menor vira o maior:
intcomlongdálong; qualquer coisa comdoubledádouble.
A regra 1 produz um erro que surpreende todo mundo:
public class Main {
public static void main(String[] args) {
byte a = 10;
byte b = 20;
byte soma = a + b;
}
}
$ javac Main.java
Main.java:5: error: incompatible types: possible lossy conversion from int to byte
byte soma = a + b;
^
1 error
"Mas eu só somei dois bytes!" Sim, só que a + b é calculado como int (regra 1), e guardar um int num byte é estreitamento. Repare que o ^ aponta para o +: é a conta que tem tipo int. Há duas saídas: guardar num int ou fazer o casting do resultado inteiro, com parênteses em volta da conta:
public class Main {
public static void main(String[] args) {
byte a = 10;
byte b = 20;
byte soma = (byte) (a + b);
int somaInt = a + b;
System.out.println(soma);
System.out.println(somaInt);
short s = 1;
char c = 'A';
System.out.println(s + c);
int i = 5;
long l = 10L;
float f = 1.5f;
double d = 2.0;
System.out.println(i + l);
System.out.println(i + f);
System.out.println(l + d);
System.out.println(5 / 2 * 2.0);
System.out.println(5 * 2.0 / 2);
System.out.println(5 / 2.0 * 2);
}
}
$ javac Main.java && java Main 30 30 66 « short + char: os dois viram int (1 + 65) 15 « int + long = long 6.5 « int + float = float 12.0 « long + double = double 4.0 « 5 / 2 = 2 (inteiros!), depois 2 * 2.0 = 4.0 5.0 « 5 * 2.0 = 10.0, depois 10.0 / 2 = 5.0 5.0 « 5 / 2.0 = 2.5, depois 2.5 * 2 = 5.0
As três últimas linhas mostram que a promoção acontece a cada operação, da esquerda para a direita. Em 5 / 2 * 2.0, a primeira operação (5 / 2) só tem inteiros e perde o .5 antes de o 2.0 entrar na história. Por isso, ao calcular médias e porcentagens, coloque o valor decimal (ou o casting) no começo da conta. A ordem das operações é o assunto de Precedência.
| Os dois lados da conta | Resultado |
|---|---|
byte, short, char, int (qualquer mistura) | int |
algum long (e nenhum decimal) | long |
algum float (e nenhum double) | float |
algum double | double |
algum String com + | String (concatenação) |
b += 1 funciona com byte?
Os operadores compostos (+=, -=…) fazem o casting de volta sozinhos. É um detalhe importante, explicado em Operadores de Atribuição.
Quando dá errado
O que quer dizer: você tentou guardar um valor de um tipo maior num menor sem casting. A mensagem diz de qual tipo para qual: from double to int, from long to int, from int to byte.
Como consertar: primeiro pergunte se o tipo da variável está certo (talvez ela devesse ser double). Se a perda for aceitável, use casting: (int) valor. Se a ideia era arredondar, (int) Math.round(valor).
$ javac Main.java
Main.java:4: error: incompatible types: String cannot be converted to int
int numero = texto;
^
1 error
$ javac Main.java
Main.java:4: error: incompatible types: int cannot be converted to String
String texto = idade;
^
1 error
O que quer dizer: texto e número não se convertem por atribuição nem por casting.
Como consertar: int numero = Integer.parseInt(texto); e String texto = String.valueOf(idade);.
$ javac Main.java && java Main Exception in thread "main" java.lang.NumberFormatException: For input string: "3.5" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) at java.base/java.lang.Integer.parseInt(Integer.java:565) at java.base/java.lang.Integer.parseInt(Integer.java:662) at Main.main(Main.java:3)
O que quer dizer: o texto entre aspas não é um inteiro válido. Olhe com atenção o que está entre as aspas: espaços, vírgulas, pontos e letras aparecem ali.
Como consertar: use o método certo para o formato (Double.parseDouble para "3.5"), limpe espaços com strip(), ou trate o erro com try e catch.
O que aconteceu: (byte) 200 deu -56, (int) 9.99 deu 9, (double) (7 / 2) deu 3.0. Não é erro do Java: é exatamente o que o casting promete. Ele corta, dá a volta, e só converte o valor que está à sua direita.
Como consertar: confira se o valor cabe no tipo de destino, use Math.round para arredondar e coloque o casting antes da divisão: (double) soma / n.
Missão (provoque o erro): mude o texto "150" de modo que o Integer.parseInt lance NumberFormatException. Tente algumas formas diferentes (letras, vírgula, espaço) e leia a mensagem de cada uma.
public class Main {
public static void main(String[] args) {
String estoqueTexto = "150";
int estoque = Integer.parseInt(estoqueTexto);
System.out.println("Estoque: " + estoque);
}
}
public class Main {
public static void main(String[] args) {
String estoqueTexto = "150 caixas";
int estoque = Integer.parseInt(estoqueTexto);
System.out.println("Estoque: " + estoque);
}
}
Referência
| Conversão | Como | Exemplo → resultado |
|---|---|---|
| Menor → maior | Automática | double d = 32; → 32.0 |
| Maior → menor | (tipo) valor | (int) 9.99 → 9 |
| Decimal → inteiro arredondado | Math.round(x) (devolve long) | Math.round(9.99) → 10 |
Número → String | String.valueOf(n), "" + n, Integer.toString(n) | "29" |
String → int | Integer.parseInt(s) | Integer.parseInt("42") → 42 |
String → double | Double.parseDouble(s) | Double.parseDouble("1.65") → 1.65 |
String → long | Long.parseLong(s) | |
char → código | (int) c | (int) 'A' → 65 |
| Dígito → número | c - '0', Character.getNumericValue(c) | '7' → 7 |
boolean ↔ número | Não existe; use b ? 1 : 0 ou n != 0 |
Exercícios
1. Casting
Complete para guardar a parte inteira de altura (um double):
2. Texto para número
Complete para transformar o texto "35" em int:
3. Número para texto
Complete com o método que transforma qualquer valor em String:
4. O que System.out.println((int) 7.9); mostra?
5. Por que byte soma = a + b; (com a e b do tipo byte) não compila?
6. O que acontece com Integer.parseInt("12,5")?
7. Qual destas expressões dá 3.5?
Resumo
- Alargamento (menor → maior:
byte → short → int → long → float → double, echar → int) é automático. - Estreitamento exige casting,
(int) valor, e pode perder informação: corta decimais ((int) 9.99= 9) ou dá a volta ((byte) 200= -56). Para arredondar,Math.round. - O casting vale para o valor logo à direita:
(double) 7 / 2= 3.5, mas(double) (7 / 2)= 3.0. - Texto → número:
Integer.parseInt,Double.parseDouble; texto inválido lançaNumberFormatExceptionna execução. Número → texto:String.valueOf. '7'vale 55 comoint; para o número 7, use'7' - '0'.- Nas contas,
byte,shortecharviramint, e o tipo menor vira o maior:byte + byteéint.