Java Operadores de Comparação

Programas tomam decisões o tempo todo: "a nota é suficiente para passar?", "o estoque acabou?", "a senha está certa?". Cada uma dessas perguntas é uma comparação, e a resposta é sempre sim ou não: true ou false. Nesta aula você vai conhecer os seis operadores de comparação do Java e as armadilhas de comparar textos e números decimais.

Você vai aprender
  • Os operadores ==, !=, >, <, >= e <=.
  • Que toda comparação produz um boolean, que pode ser guardado numa variável.
  • O que dá para comparar: números, char e boolean.
  • Por que não usar == com String nem com double.
  • Os erros mais comuns, como 18 <= idade < 60 e = no lugar de ==.

Os seis operadores

São os sinais da matemática da escola, escritos com os caracteres do teclado. A Ana tirou 7 na prova:

public class Main {
    public static void main(String[] args) {
        int nota = 7;
        System.out.println(nota == 7);
        System.out.println(nota != 7);
        System.out.println(nota > 6);
        System.out.println(nota < 6);
        System.out.println(nota >= 7);
        System.out.println(nota <= 5);
    }
}
$ javac Main.java && java Main
true               « 7 é igual a 7
false              « 7 é diferente de 7? não
true
false
true               « 7 é maior OU igual a 7
false
OperadorPerguntaNa matemáticaExemplo (nota = 7)
==É igual?=nota == 7 → true
!=É diferente?≠nota != 7 → false
>É maior?>nota > 6 → true
<É menor?<nota < 6 → false
>=É maior ou igual?≥nota >= 7 → true
<=É menor ou igual?≤nota <= 5 → false

Detalhes de escrita que causam erro (todos com a mensagem real em Quando dá errado):

  • Igualdade usa dois sinais: ==. Um só (=) é atribuição, assunto de Operadores de Atribuição.
  • Os sinais de dois caracteres são escritos juntos e na ordem certa: >= e <= (nunca =>, =< ou = =). Dica: leia em voz alta, "maior ou igual": o > vem primeiro.
  • != vem do !, que em Java quer dizer "não": "não igual".

O resultado é um boolean

Uma comparação não é uma ordem, é uma pergunta, e a resposta é um valor do tipo boolean (char e boolean). Como qualquer valor, ele pode ser guardado numa variável, impresso ou usado em outra conta:

public class Main {
    public static void main(String[] args) {
        int idade = 17;
        double altura = 1.65;
        boolean maiorDeIdade = idade >= 18;
        boolean podeBrincar = altura >= 1.40;
        System.out.println("Maior de idade? " + maiorDeIdade);
        System.out.println("Pode ir no brinquedo? " + podeBrincar);
        System.out.println(5 == 5.0);
        System.out.println('a' < 'b');
        System.out.println('Z' < 'a');
        System.out.println('A' == 65);
        System.out.println(true == false);
        System.out.println("Resultado: " + (3 > 2));
    }
}
$ javac Main.java && java Main
Maior de idade? false
Pode ir no brinquedo? true
true               « 5 == 5.0: o int vira double e os valores são iguais
true               « 'a' (97) < 'b' (98)
true               « 'Z' (90) < 'a' (97): maiúsculas vêm antes!
true               « 'A' é o código 65
false
Resultado: true
boolean
O tipo da variável: guarda true ou false.
maiorDeIdade
Um nome que soa como pergunta.
=
Atribuição: guarda o resultado da direita.
idade >= 18
A comparação, calculada primeiro: 17 >= 18 é false.

Na última linha, os parênteses em (3 > 2) são necessários: sem eles, o Java tentaria colar "Resultado: " + 3 antes de comparar, e o código não compilaria (veja Precedência).

O que dá para comparar

Tipos== e !=> < >= <=Observação
Números (int, double…), misturados ou nãoSimSimO menor tipo é convertido: 5 == 5.0 é true. Cuidado com double (abaixo).
charSimSimCompara os códigos Unicode: 'A' < 'Z' < 'a' < 'z'.
booleanSimNãotrue > false não compila.
String e outros objetosCompila, mas enganaNãoUse equals e compareTo (abaixo).
Não compare boolean com true

if (pago == true) funciona, mas é redundante: pago já é true ou false. Escreva if (pago). Para o contrário, if (!pago) em vez de if (pago == false). O ! está em Operadores Lógicos.

Missão: no Brasil, pode votar quem tem 16 anos ou mais. O programa diz que alguém de 16 anos não pode. Corrija o operador de comparação para mostrar Pode votar? true.

public class Main {
    public static void main(String[] args) {
        int idade = 16;
        boolean podeVotar = idade > 16;
        System.out.println("Pode votar? " + podeVotar);
    }
}
public class Main {
    public static void main(String[] args) {
        int idade = 16;
        boolean podeVotar = idade >= 16;
        System.out.println("Pode votar? " + podeVotar);
    }
}

A armadilha: == com String

Com tipos primitivos, == compara valores. Com objetos, como String, == compara outra coisa: se as duas variáveis apontam para o mesmo objeto na memória. Dois textos iguais podem estar em objetos diferentes:

public class Main {
    public static void main(String[] args) {
        String a = "Ana";
        String b = "Ana";
        String c = new String("Ana");
        System.out.println(a == b);
        System.out.println(a == c);
        System.out.println(a.equals(c));
    }
}
$ javac Main.java && java Main
true               « a e b: por acaso, o mesmo objeto
false              « a e c: mesmo texto, objetos diferentes!
true               « equals compara o TEXTO

O resultado de == depende de como a String foi criada, e textos digitados pelo usuário ou lidos de arquivos quase sempre são objetos novos. Por isso a regra é simples: para comparar textos, use equals: nome.equals("Ana"). A explicação completa, com a "prova real" e o equalsIgnoreCase, está em Strings. E < e > nem compilam com String; para ordem alfabética, existe compareTo, também em Strings.

Regra de bolso

Primitivos (int, double, char, boolean): ==. Objetos (String e tudo que começa com maiúscula): equals.


Comparar double

Como você viu em double e float, contas com decimais acumulam pequenos erros. Uma comparação com == pode falhar mesmo quando "deveria" dar certo:

public class Main {
    public static void main(String[] args) {
        double total = 0.1 + 0.2;
        System.out.println(total == 0.3);
        System.out.println(Math.abs(total - 0.3) < 1e-9);
        double nada = 0.0 / 0;
        System.out.println(nada == nada);
        System.out.println(nada != nada);
        System.out.println(Double.isNaN(nada));
        System.out.println(0.1 + 0.2 > 0.3);
    }
}
$ javac Main.java && java Main
false              « 0.30000000000000004 não é 0.3
true               « com tolerância: "a diferença é menor que 0,000000001?"
false              « NaN não é igual nem a si mesmo
true
true
true               « 0.1 + 0.2 é (um pouquinho) MAIOR que 0.3
Para saber se…Não useUse
dois double são "iguais"a == bMath.abs(a - b) < 1e-9 (a tolerância depende do problema)
um valor é NaNx == Double.NaN (sempre false)Double.isNaN(x)
um valor passou de um limite—>, <, >=, <= funcionam bem, exceto exatamente na fronteira

1e-9 é notação científica: 1 × 10-9, ou 0,000000001.

Missão: confirme no JShell que 0.1 + 0.2 == 0.3 dá false. Depois teste Math.abs(0.1 + 0.2 - 0.3) < 1e-9.

0.1 + 0.2 == 0.3

Quando dá errado

18 <= idade < 60: "bad operand types for binary operator '<'"
public class Main {
    public static void main(String[] args) {
        int idade = 25;
        System.out.println(18 <= idade < 60);
    }
}
$ javac Main.java
Main.java:4: error: bad operand types for binary operator '<'
        System.out.println(18 <= idade < 60);
                                       ^
  first type:  boolean
  second type: int
1 error

O que quer dizer: na matemática, "18 ≤ idade < 60" é uma frase só. Em Java, cada operador compara dois valores, da esquerda para a direita: primeiro 18 <= idade vira true, e depois o Java tentaria true < 60. Os tipos dos dois lados aparecem no erro: first type: boolean, second type: int. Comparar um boolean com um número não faz sentido.

Como consertar: faça duas comparações e junte com && ("e"): idade >= 18 && idade < 60. O && é o assunto da próxima aula, Operadores Lógicos.

Missão: o cinema cobra inteira de quem tem de 18 a 59 anos. O programa não compila. Reescreva a comparação com duas partes ligadas por && para que ele mostre Paga meia? false.

public class Main {
    public static void main(String[] args) {
        int idade = 25;
        boolean pagaInteira = 18 <= idade < 60;
        System.out.println("Paga meia? " + !pagaInteira);
    }
}
public class Main {
    public static void main(String[] args) {
        int idade = 25;
        boolean pagaInteira = idade >= 18 && idade < 60;
        System.out.println("Paga meia? " + !pagaInteira);
    }
}
Tipos que não se comparam: "bad operand types for binary operator '=='"
$ javac Main.java
Main.java:4: error: bad operand types for binary operator '=='
        System.out.println(letra == "a");
                                 ^
  first type:  char
  second type: String
1 error

O que quer dizer: letra é um char e "a", com aspas duplas, é uma String. Tipos sem relação não podem ser comparados. O mesmo erro aparece em nome == idade (String com int), em pago > false (boolean com >) e em "abacaxi" < "banana" (String com <).

Como consertar: compare valores do mesmo tipo: letra == 'a', com aspas simples. Para textos, equals e compareTo.

Sinais na ordem errada: =>, =<, = =
$ javac Main.java
Main.java:4: error: illegal start of expression
        System.out.println(x => 3);
                              ^
1 error
$ javac Main.java
Main.java:4: error: illegal start of type
        System.out.println(x =< 3);
                                ^
1 error

O que quer dizer: o Java leu um = (atribuição) seguido de um > ou < solto, que não podem começar uma expressão. Com espaço no meio, x = = 5 também dá illegal start of expression. As mensagens não falam em "operador errado", mas o ^ aponta para o lugar.

Como consertar: >=, <= e ==, juntos, com o = sempre por último.

= no lugar de == num if: "int cannot be converted to boolean"

O que quer dizer: if (idade = 18) atribui em vez de comparar, e o resultado (um int) não serve de condição. O erro real está em Operadores de Atribuição.

Como consertar: if (idade == 18).

A comparação de textos deu false com textos iguais

O que aconteceu: você usou == com String. Compila, mas compara se é o mesmo objeto, não o mesmo texto.

Como consertar: texto1.equals(texto2). Veja Strings.


Referência

OperadorSignificadoExemplo → resultado
a == bIgual (primitivos)7 == 7 → true
a != bDiferente7 != 7 → false
a > bMaior7 > 6 → true
a < bMenor'a' < 'b' → true
a >= bMaior ou igual7 >= 7 → true
a <= bMenor ou igual7 <= 5 → false
s1.equals(s2)Mesmo texto (String)"Ana".equals(nome)
Math.abs(a - b) < tol"Iguais" para doubleMath.abs(0.1 + 0.2 - 0.3) < 1e-9 → true
Double.isNaN(x)x é NaN?
min <= x && x <= maxEstá entre dois valoresVeja Operadores Lógicos

Exercícios

1. Diferente

Complete com o operador "diferente de":

boolean mudou = senhaNova senhaAntiga;

2. Aprovação

Aprova quem tira 6 ou mais. Complete:

boolean aprovado = nota 6;

3. Textos

Complete para comparar o texto de nome com "Ana":

boolean ehAna = nome.("Ana");

4. Qual o tipo do resultado de idade > 18?

5. O que System.out.println('Z' < 'a'); mostra?

6. Por que 18 <= idade < 60 não compila?

7. Qual o jeito certo de saber se o double total "vale" 0.3?


Resumo

  • Seis operadores: ==, !=, >, <, >=, <=. Igualdade tem dois sinais; os compostos têm o = por último.
  • Toda comparação dá um boolean, que pode ser guardado: boolean aprovado = nota >= 6;.
  • Números se comparam entre si (5 == 5.0 é true); char compara códigos Unicode; boolean só com == e !=.
  • String: use equals, não ==.
  • double: compare com tolerância; NaN se testa com Double.isNaN.
  • "Entre dois valores" são duas comparações: x >= 18 && x < 60.