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.

Você vai aprender
  • 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.5 dá 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
UsoExemplo
Singular / pluraln == 1 ? "item" : "itens"
Maior / menor de doisa > b ? a : b (o mesmo que Math.max(a, b), veja Math)
Valor padrão quando algo é nullapelido != null ? apelido : nome
Mensagem conforme a situaçãohora < 12 ? "Bom dia" : "Boa tarde"
Escolher um númerocompra >= 100 ? 0 : 15 (frete)
Parênteses quando o ternário está no meio de um +

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 valoresEscolhe entre ações (várias linhas, chamadas de métodos)
Cabe numa linha e se lê fácilA condição ou os valores são compridos
Vai guardar, imprimir ou usar o valor numa contaHá 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 outro double. O tipo comum é double (a mesma regra de 1 + 2.5, veja Conversão de Tipos). Então, mesmo escolhendo o 1, o resultado é 1.0.
inteiro ? "um" : 2
String com int não têm tipo numérico comum; o resultado vira um "objeto qualquer" (Object). O println aceita qualquer objeto, por isso funcionou. Mas guardar isso numa variável String nã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

FormaResultado
cond ? a : ba 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 : cAninhado (evite; prefira else if ou switch)
cond ? 1 : 2.5Tipo 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:

String sinal = n < 0 ;

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ão a, senão b". O resultado é um valor.
  • Use para escolher entre dois valores (plural, maior, valor padrão, mensagem); use if/else para 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 if ou switch.
  • Os dois lados devem ser do mesmo tipo: cond ? 1 : 2.5 é double.