Java Operador Ternário
Muitas vezes um if/else existe só para escolher entre dois valores: "aprovada" ou "reprovada", "item" ou "itens", "bom dia" ou "boa tarde". Para esses casos, o Java tem um atalho que cabe numa linha: o operador ternário, escrito condição ? valor1 : valor2.
- Como ler e escrever
condição ? a : b. - Quando o ternário deixa o código mais claro, e quando o
if/elseé melhor. - Usos típicos: plural, maior de dois números, valor padrão quando algo é
null. - Ternários aninhados, e por que evitá-los.
- O que acontece com os tipos dos dois lados (por que
true ? 1 : 2.5dá1.0). - Os erros reais:
not a statement,: expected,bad type in conditional expression.
A ideia: uma pergunta com duas respostas prontas
Pense no garçom que pergunta "com açúcar ou sem?". Antes de você responder, as duas opções já estão prontas; a sua resposta só escolhe qual vai para a mesa. O ternário é isso: uma pergunta (true ou false) e duas respostas prontas. O resultado é um valor, que você guarda, imprime ou usa numa conta.
O nome "ternário" vem de três: é o único operador do Java com três partes (o + tem duas, o ! tem uma). O nome oficial é operador condicional.
Do if/else ao ternário
Os dois trechos abaixo fazem exatamente a mesma coisa:
public class Main {
public static void main(String[] args) {
double nota = 8.5;
String situacao1;
if (nota >= 7.0) {
situacao1 = "aprovada";
} else {
situacao1 = "reprovada";
}
String situacao2 = nota >= 7.0 ? "aprovada" : "reprovada";
System.out.println(situacao1);
System.out.println(situacao2);
}
}
$ java Main.java aprovada aprovada
- nota >= 7.0
- A condição: uma expressão booleana. Não precisa de parênteses (mas pode ter, se ajudar a ler).
- ?
- Lê-se "então". Separa a pergunta das respostas.
- "aprovada"
- O valor do resultado quando a condição é
true. - :
- Lê-se "senão".
- "reprovada"
- O valor quando a condição é
false.
Leia em voz alta: "situação recebe: nota maior ou igual a 7? então 'aprovada', senão 'reprovada'". Seis linhas viraram uma, e a variável já nasce com o valor (não fica "sem valor" nem por um instante).
Missão: use o ternário para que periodo seja "manhã" quando a hora for menor que 12, e "tarde" caso contrário. Com hora = 9, a saída deve ser Período: manhã. Depois teste com 15.
public class Main {
public static void main(String[] args) {
int hora = 9;
String periodo = ""; // troque "" pelo ternário
System.out.println("Período: " + periodo);
}
}
public class Main {
public static void main(String[] args) {
int hora = 9;
String periodo = hora < 12 ? "manhã" : "tarde";
System.out.println("Período: " + periodo);
}
}
Onde o ternário brilha
Como o ternário é uma expressão (produz um valor), ele cabe em lugares onde um if não cabe: no meio de uma conta, de uma concatenação, de um println.
public class Main {
public static void main(String[] args) {
int itens = 1;
System.out.println("Você tem " + itens + (itens == 1 ? " item" : " itens") + " no carrinho.");
itens = 3;
System.out.println("Você tem " + itens + (itens == 1 ? " item" : " itens") + " no carrinho.");
int a = 7, b = 12;
int maior = a > b ? a : b;
System.out.println("Maior: " + maior);
String apelido = null;
String nome = "Ana Souza";
String exibido = apelido != null ? apelido : nome;
System.out.println("Olá, " + exibido);
int hora = 14;
System.out.println(hora < 12 ? "Bom dia" : "Boa tarde");
}
}
$ java Main.java Você tem 1 item no carrinho. « singular Você tem 3 itens no carrinho. « plural Maior: 12 Olá, Ana Souza « sem apelido, usa o nome Boa tarde
| Uso | Exemplo |
|---|---|
| Singular / plural | n == 1 ? "item" : "itens" |
| Maior / menor de dois | a > b ? a : b (o mesmo que Math.max(a, b), veja Math) |
Valor padrão quando algo é null | apelido != null ? apelido : nome |
| Mensagem conforme a situação | hora < 12 ? "Bom dia" : "Boa tarde" |
| Escolher um número | compra >= 100 ? 0 : 15 (frete) |
+
Repare em "Você tem " + itens + (itens == 1 ? " item" : " itens"). O ternário tem uma das prioridades mais baixas de todos os operadores (veja Precedência). Sem os parênteses, o Java faria primeiro as concatenações e só depois a comparação, e o resultado não compila (veja "Quando dá errado").
Ternário comprido? Quebre em linhas
Quando os valores são longos, alinhe o ? e o : em linhas separadas. Continua sendo uma expressão só:
public class Main {
public static void main(String[] args) {
double nota = 8.0;
System.out.println(nota >= 7 ? "Aprovada" : "Reprovada");
String msg = nota >= 7
? "Parabéns, você passou!"
: "Não desanime, estude mais.";
System.out.println(msg);
}
}
$ java Main.java Aprovada Parabéns, você passou!
Quando não usar
O ternário escolhe um valor. Ele não serve para escolher entre duas ações (mostrar uma coisa ou outra, gravar um arquivo ou não). Para isso, use if/else. Tentar fazer uma ação com ternário nem compila:
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
double nota = 8.0;
nota >= 7 ? System.out.println("Aprovada") : System.out.println("Reprovada");
}
}
$ javac Main.java
Main.java:4: error: not a statement
nota >= 7 ? System.out.println("Aprovada") : System.out.println("Reprovada");
^
1 error
"Não é uma instrução": um ternário sozinho numa linha é um valor que ninguém usa, como escrever só 5;. Além disso, println não devolve valor nenhum (é void), então não pode ser uma das respostas. Escolha o texto com o ternário e chame o println uma vez só: System.out.println(nota >= 7 ? "Aprovada" : "Reprovada");.
| Use o ternário quando… | Use if/else quando… |
|---|---|
| Escolhe entre dois valores | Escolhe entre ações (várias linhas, chamadas de métodos) |
| Cabe numa linha e se lê fácil | A condição ou os valores são compridos |
| Vai guardar, imprimir ou usar o valor numa conta | Há mais de duas opções (prefira else if ou switch) |
Ternário dentro de ternário
As respostas de um ternário podem ser outro ternário. Isso permite escolher entre três ou mais valores:
public class Main {
public static void main(String[] args) {
double nota = 7.8;
String conceito = nota >= 9 ? "A" : nota >= 7 ? "B" : nota >= 5 ? "C" : "D";
System.out.println(conceito);
}
}
$ java Main.java B
Funciona: o Java lê como uma escada de else if (a parte depois de cada : é o "senão"). Mas compare com a versão da aula if, else if, else: qual você entende mais rápido? Num ternário aninhado é fácil errar a ordem e difícil achar o erro. Por isso a maioria dos guias de estilo recomenda evitar ternários aninhados. Se precisar de um, use parênteses e quebras de linha para deixar a estrutura visível:
String t = idade >= 18 ? "adulto"
: (idade >= 12 ? "adolescente" : "criança");
Para várias opções, o switch com setas costuma ser a escolha mais clara.
Os tipos dos dois lados
O resultado do ternário tem um tipo só, decidido na hora de compilar, antes de saber qual lado vai ganhar. Se os dois lados têm tipos diferentes, o Java tenta achar um tipo que sirva para os dois. Isso dá algumas surpresas:
public class Main {
public static void main(String[] args) {
boolean inteiro = true;
System.out.println(inteiro ? 1 : 2.5);
var x = inteiro ? 1 : 2.5;
System.out.println(x);
System.out.println(inteiro ? "um" : 2);
}
}
$ java Main.java 1.0 « o lado escolhido foi o 1 (int)… mas virou double! 1.0 « o tipo de x é double um
- inteiro ? 1 : 2.5
- Um lado é
int, o outrodouble. O tipo comum édouble(a mesma regra de1 + 2.5, veja Conversão de Tipos). Então, mesmo escolhendo o1, o resultado é1.0. - inteiro ? "um" : 2
- String com
intnão têm tipo numérico comum; o resultado vira um "objeto qualquer" (Object). Oprintlnaceita qualquer objeto, por isso funcionou. Mas guardar isso numa variávelStringnão compila (veja abaixo).
Regra prática: faça os dois lados do mesmo tipo. Dois textos, dois int, dois double.
Quando dá errado
error: incompatible types: bad type in conditional expression
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
boolean ativo = true;
String texto = ativo ? "ligado" : 0;
System.out.println(texto);
}
}
$ javac Main.java
Main.java:4: error: incompatible types: bad type in conditional expression
String texto = ativo ? "ligado" : 0;
^
int cannot be converted to String
1 error
O que aconteceu: "tipo inválido na expressão condicional". O resultado vai para uma String, e um dos lados é o int 0, que não vira String sozinho (a linha de baixo explica: int cannot be converted to String). O ^ aponta o lado culpado.
Como resolver: os dois lados do mesmo tipo: ativo ? "ligado" : "desligado" (ou "0", entre aspas).
error: not a statement
O que aconteceu: o ternário foi usado sozinho numa linha, para escolher entre duas ações (veja "Quando não usar").
Como resolver: use if/else, ou use o ternário para escolher o valor e faça a ação uma vez: System.out.println(cond ? "a" : "b");.
error: : expected
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
double nota = 8.0;
String s = nota >= 7 ? "aprovada";
System.out.println(s);
}
}
$ javac Main.java
Main.java:4: error: : expected
String s = nota >= 7 ? "aprovada";
^
1 error
O que aconteceu: "esperava :". O ternário sempre tem as duas respostas; não existe "ternário sem senão", porque a variável precisa receber algum valor nos dois casos.
Como resolver: acrescente : "reprovada". Se no outro caso você não quer fazer nada, o que você quer é um if sem else.
error: bad operand types for binary operator '=='
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
int itens = 3;
System.out.println("Itens: " + itens == 1 ? "um" : "vários");
}
}
$ javac Main.java
Main.java:4: error: bad operand types for binary operator '=='
System.out.println("Itens: " + itens == 1 ? "um" : "vários");
^
first type: String
second type: int
1 error
O que aconteceu: sem parênteses, o + vem primeiro: "Itens: " + itens virou o texto "Itens: 3", e o Java tentou comparar esse texto com o número 1 (first type: String, second type: int).
Como resolver: parênteses em volta do ternário: "Itens: " + (itens == 1 ? "um" : "vários").
Referência
| Forma | Resultado |
|---|---|
cond ? a : b | a se cond for true; b se for false |
tipo x = cond ? a : b; | Guarda o valor escolhido |
"…" + (cond ? a : b) + "…" | No meio de uma concatenação (com parênteses) |
c1 ? a : c2 ? b : c | Aninhado (evite; prefira else if ou switch) |
cond ? 1 : 2.5 | Tipo double: o 1 vira 1.0 |
Exercícios
Missão final: usando ternários (sem if), mostre Turma com 5 alunos (no singular se fosse 1: Turma com 1 aluno) e calcule o frete: 0 para compras de 100 ou mais, 15 para as outras. Com compra = 80, a segunda linha deve ser Frete: 15.
public class Main {
public static void main(String[] args) {
int alunos = 5;
double compra = 80.0;
// mostre a turma e o frete
}
}
public class Main {
public static void main(String[] args) {
int alunos = 5;
double compra = 80.0;
System.out.println("Turma com " + alunos + (alunos == 1 ? " aluno" : " alunos"));
int frete = compra >= 100 ? 0 : 15;
System.out.println("Frete: " + frete);
}
}
1. Complete
Complete para que sinal seja "negativo" quando n < 0 e "positivo" caso contrário:
2. O resultado
Com int x = 4;, quanto vale x % 2 == 0 ? x / 2 : x * 3 + 1?
3. O tipo
O que System.out.println(false ? 10 : 3.5); mostra?
4. E System.out.println(true ? 10 : 3.5);?
5. Em qual situação o if/else é melhor que o ternário?
Resumo
condição ? a : b: "condição? entãoa, senãob". O resultado é um valor.- Use para escolher entre dois valores (plural, maior, valor padrão, mensagem); use
if/elsepara escolher entre ações. - Sempre tem as duas partes (
?e:); sozinho numa linha dánot a statement. - No meio de uma concatenação, coloque-o entre parênteses.
- Evite ternários aninhados; para várias opções,
else ifouswitch. - Os dois lados devem ser do mesmo tipo:
cond ? 1 : 2.5édouble.