Java Precedência

Quanto é 2 + 3 * 4? Se você fizer da esquerda para a direita, dá 20; se fizer a multiplicação antes, dá 14. O Java precisa de uma regra para não haver dúvida, e essa regra se chama precedência de operadores: quais operações são feitas primeiro. Nesta aula, a última sobre operadores, você vai ver a tabela completa, os casos que mais confundem (principalmente com texto) e o melhor remédio para tudo isso: parênteses.

Você vai aprender
  • O que são precedência e associatividade.
  • A tabela de precedência dos operadores do Java.
  • Por que "a" + 1 + 2 dá a12, mas 1 + 2 + "a" dá 3a.
  • A ordem entre comparações, &&, || e atribuição.
  • Quando e como usar parênteses para deixar o código claro.

A ideia: a mesma regra da escola

Na escola você aprendeu que "multiplicação e divisão vêm antes de soma e subtração" e que "o que está entre parênteses vem primeiro". O Java segue exatamente essas regras e acrescenta os operadores que não existem na matemática da escola (%, ==, &&, =…).

public class Main {
    public static void main(String[] args) {
        System.out.println(2 + 3 * 4);
        System.out.println((2 + 3) * 4);
        System.out.println(10 - 4 - 3);
        System.out.println(10 - (4 - 3));
        System.out.println(100 / 10 / 5);
        System.out.println(10 / 2 * 5);
        System.out.println(10 / (2 * 5));
        System.out.println(7 + 8 / 2);
        System.out.println((7 + 8) / 2);
        System.out.println(-2 * -3);
        System.out.println(2 * 3 % 4);
    }
}
$ javac Main.java && java Main
14                 « 3 * 4 primeiro, depois 2 + 12
20                 « parênteses primeiro: 5 * 4
3                  « (10 - 4) - 3: da esquerda para a direita
9                  « 10 - 1
2                  « (100 / 10) / 5
25                 « (10 / 2) * 5, NÃO 10 / 10
1                  « 10 / 10
11                 « 7 + 4: a "média" errada!
7                  « 15 / 2 = 7 (divisão inteira)
6                  « o sinal (-) vem antes da multiplicação
2                  « (2 * 3) % 4 = 6 % 4

Duas regras explicam todas essas linhas:

Precedência
Entre operadores diferentes, qual vem primeiro. *, / e % têm precedência maior que + e -, por isso 2 + 3 * 4 é 2 + (3 * 4).
Associatividade
Entre operadores de mesma precedência, de que lado se começa. Quase todos vão da esquerda para a direita: 10 - 4 - 3 é (10 - 4) - 3, e 10 / 2 * 5 é (10 / 2) * 5.

A linha 10 / 2 * 5 engana muita gente: * e / têm a mesma precedência, então não é "multiplicação primeiro"; é "quem estiver à esquerda primeiro".

Missão: no JShell, calcule 2 + 3 * 4 e confira que dá 14. Depois coloque parênteses para obter 20, e teste 10 / 2 * 5.

2 + 3 * 4

A tabela de precedência

Da maior precedência (feito primeiro) para a menor (feito por último). Operadores na mesma linha têm a mesma precedência. Você não precisa decorar a tabela: decore as quatro ou cinco regras do resumo e use parênteses no resto.

OrdemOperadoresNomeAssociatividade
1x++ x-- () . []Pós-fixos, chamada de método, acesso a membro e a arrayesquerda → direita
2++x --x +x -x ! ~ (tipo)Unários e castingdireita → esquerda
3* / %Multiplicativosesquerda → direita
4+ -Aditivos (e concatenação de String)esquerda → direita
5<< >> >>>Deslocamento de bitsesquerda → direita
6< > <= >= instanceofRelacionaisesquerda → direita
7== !=Igualdadeesquerda → direita
8&E de bits / E sem curto-circuitoesquerda → direita
9^Ou exclusivoesquerda → direita
10|Ou de bits / Ou sem curto-circuitoesquerda → direita
11&&E lógicoesquerda → direita
12||Ou lógicoesquerda → direita
13? :Ternáriodireita → esquerda
14= += -= *= /= %= …Atribuiçãodireita → esquerda

Em resumo, de cima para baixo: unários → aritmética (multiplicação antes de soma) → comparações → lógicos (&& antes de ||) → atribuição. Faz sentido: primeiro se calculam os números, depois se comparam, depois se combinam as comparações e, por último, o resultado é guardado.


Texto e números: "a" + 1 + 2 × 1 + 2 + "a"

O + tem dois papéis: soma números e cola textos (Concatenação). Como ele vai da esquerda para a direita, o papel muda no meio da expressão, assim que aparece um texto:

public class Main {
    public static void main(String[] args) {
        System.out.println("a" + 1 + 2);
        System.out.println(1 + 2 + "a");
        System.out.println("a" + (1 + 2));
        System.out.println(1 + 2 + "a" + 1 + 2);
        System.out.println("Total: " + 2 * 3);
        System.out.println("Total: " + 10 / 2);
        System.out.println('a' + 'b' + "c");
        System.out.println("c" + 'a' + 'b');
    }
}
$ javac Main.java && java Main
a12                « ("a" + 1) + 2 = "a1" + 2 = "a12"
3a                 « (1 + 2) + "a" = 3 + "a" = "3a"
a3                 « parênteses: a soma acontece antes
3a12               « soma até aparecer o texto, depois só cola
Total: 6           « * vem antes de +: não precisa de parênteses
Total: 5           « / também
195c               « 'a' + 'b' = 97 + 98 = 195 (números!), depois cola "c"
cab                « começando com texto, tudo é colado

Acompanhe passo a passo a quarta linha, 1 + 2 + "a" + 1 + 2:

  1. 1 + 2: dois números, soma. Resultado: 3.
  2. 3 + "a": um dos lados é texto, então cola. Resultado: "3a".
  3. "3a" + 1: texto com número, cola. Resultado: "3a1".
  4. "3a1" + 2: cola. Resultado final: "3a12".

E por que "Total: " + 2 * 3 funciona sem parênteses? Porque * tem precedência maior que +: a multiplicação acontece antes de qualquer colagem. Já "Total: " + 2 + 3 mostraria Total: 23. Para somar dentro de um texto, sempre parênteses: "Total: " + (2 + 3).

Missão: o programa deveria mostrar Soma: 15, mas mostra Soma: 105. Use parênteses para a soma acontecer antes da colagem.

public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 5;
        System.out.println("Soma: " + a + b);
    }
}
public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 5;
        System.out.println("Soma: " + (a + b));
    }
}

Comparações, lógicos e atribuição

public class Main {
    public static void main(String[] args) {
        int a, b, c;
        a = b = c = 5;
        System.out.println(a + " " + b + " " + c);
        int x = 10;
        x += x * 2;
        System.out.println(x);
        boolean r = 5 > 3 == true;
        System.out.println(r);
        System.out.println(1 + 2 == 3);
        System.out.println(true || false && false);
        System.out.println(!false && false);
        System.out.println(!(false && false));
        int idade = 20;
        System.out.println(idade >= 18 && idade < 60 || idade == 0);
        int i = 5;
        int j = i++ + ++i;
        System.out.println(i + " " + j);
        double media = (double) 7 / 2;
        System.out.println(media);
        System.out.println((double) (7 / 2));
        System.out.println(-3 % 2 + 1);
    }
}
$ javac Main.java && java Main
5 5 5              « atribuição: da direita para a esquerda
30                 « x += (x * 2): o lado direito inteiro primeiro
true               « (5 > 3) == true
true               « (1 + 2) == 3: a soma vem antes da comparação
true               « true || (false && false)
false              « (!false) && false: o ! vale só para o false
true               « !(false && false): o ! vale para tudo
true               « ((idade >= 18) && (idade < 60)) || (idade == 0)
7 12               « 5 + 7: leia a explicação abaixo
3.5                « o casting vem antes da divisão
3.0                « com parênteses, a divisão (inteira) vem antes
0                  « (-3 % 2) + 1 = -1 + 1
ExpressãoComo o Java lêRegra
a = b = c = 5a = (b = (c = 5))Atribuição associa da direita para a esquerda
x += x * 2x = x + (x * 2)Atribuição é a última de todas
1 + 2 == 3(1 + 2) == 3Aritmética antes de comparação
true || false && falsetrue || (false && false)&& antes de ||
!false && false(!false) && falseUnários antes de tudo
(double) 7 / 2((double) 7) / 2Casting é unário: vem antes da divisão

O caso i++ + ++i

Com i valendo 5, j = i++ + ++i deu 12 e i terminou em 7. O Java calcula os operandos da esquerda para a direita: i++ produz 5 e deixa i em 6; depois ++i leva i a 7 e produz 7; por fim, 5 + 7 = 12. Funciona sempre igual em Java, mas é ilegível: veja a dica sobre ++ em Operadores Aritméticos.


Use parênteses

A tabela existe, mas quem lê seu código não a tem decorada (e daqui a seis meses, nem você). Parênteses não custam nada, não deixam o programa mais lento e eliminam a dúvida. Use-os sempre que:

  • misturar && e ||: (idade >= 18 && idade < 60) || convidado;
  • fazer contas dentro de um texto: "Total: " + (preco * qtd);
  • a conta tiver uma ordem que não é a da tabela: médias, fórmulas;
  • usar casting numa expressão: (double) soma / n ou (int) (preco * 100).

As fórmulas são onde a precedência mais causa erros "silenciosos" (compila, roda, e o resultado está errado):

public class Main {
    public static void main(String[] args) {
        int n1 = 8, n2 = 6, n3 = 7;
        double media = n1 + n2 + n3 / 3.0;
        System.out.println(media);
        double certa = (n1 + n2 + n3) / 3.0;
        System.out.println(certa);
        double celsius = 25;
        double fahrenheit = celsius * 9 / 5 + 32;
        System.out.println(fahrenheit);
        double errado = celsius * (9 / 5) + 32;
        System.out.println(errado);
    }
}
$ javac Main.java && java Main
16.333333333333332 « 8 + 6 + (7 / 3.0): só o n3 foi dividido
7.0                « (8 + 6 + 7) / 3.0
77.0               « ((25 * 9) / 5) + 32: certo
57.0               « 9 / 5 entre parênteses é divisão inteira = 1!

A última linha mostra que parênteses também podem atrapalhar: (9 / 5) força a divisão de dois inteiros a acontecer sozinha, e ela dá 1. Parênteses decidem a ordem; as regras de tipo (Conversão de Tipos) continuam valendo dentro deles. Escrever 9.0 / 5 resolveria.

Missão: a média das três notas está saindo 16.333333333333332. Coloque parênteses para somar as três antes de dividir, e o programa deve mostrar 7.0.

public class Main {
    public static void main(String[] args) {
        int n1 = 8, n2 = 6, n3 = 7;
        double media = n1 + n2 + n3 / 3.0;
        System.out.println(media);
    }
}
public class Main {
    public static void main(String[] args) {
        int n1 = 8, n2 = 6, n3 = 7;
        double media = (n1 + n2 + n3) / 3.0;
        System.out.println(media);
    }
}

Quando dá errado

Comparação dentro de texto: "bad operand types for binary operator '>'"
public class Main {
    public static void main(String[] args) {
        int x = 5;
        System.out.println("x é positivo? " + x > 0);
    }
}
$ javac Main.java
Main.java:4: error: bad operand types for binary operator '>'
        System.out.println("x é positivo? " + x > 0);
                                                ^
  first type:  String
  second type: int
1 error

O que quer dizer: o + tem precedência maior que o >, então o Java colou primeiro ("x é positivo? 5") e depois tentou comparar esse texto com 0. O erro diz exatamente isso: first type: String.

Como consertar: parênteses em volta da comparação: "x é positivo? " + (x > 0). O mesmo erro aparece com o ternário, "Idade: " + idade >= 18 ? …, desta vez para o operador '>='.

!idade > 18: "bad operand type int for unary operator '!'"

O que quer dizer: o ! (unário) vem antes do >, e "não idade" não existe. O erro real está em Operadores Lógicos.

Como consertar: !(idade > 18), ou idade <= 18.

O resultado está errado, sem nenhuma mensagem

O que aconteceu: a precedência fez a conta numa ordem diferente da que você imaginou: a + b / 2 divide só o b; "Total: " + a + b cola em vez de somar; x > 0 || y > 0 && z > 0 agrupa o && primeiro.

Como consertar: escreva os parênteses que deixam a sua intenção explícita. Se quiser conferir como o Java está lendo, teste pedaços da expressão no JShell.


Referência

RegraExemplo → resultado
Parênteses primeiro(2 + 3) * 4 → 20
Unários (-, !, ++, casting) antes dos binários(double) 7 / 2 → 3.5
* / % antes de + -2 + 3 * 4 → 14
Mesma precedência: esquerda → direita10 / 2 * 5 → 25; "a" + 1 + 2 → a12
Aritmética antes de comparação1 + 2 == 3 → true
Comparação antes de && e ||x > 0 && x < 10
&& antes de ||true || false && false → true
Atribuição por último, direita → esquerdaa = b = 5

Exercícios

1. Multiplicação primeiro

Quanto vale 5 + 2 * 3?

2. Esquerda para a direita

Quanto vale 20 / 4 * 2?

3. Texto e números

O que System.out.println(2 + 3 + "x" + 2 + 3); mostra?

4. O que System.out.println("Nota: " + 7 + 1); mostra?

5. Qual expressão calcula corretamente a média de a e b (ambos int) com casas decimais?

6. Como o Java lê a || b && c?


Resumo

  • Precedência decide qual operador vem primeiro; associatividade decide o lado, entre operadores de mesma precedência (quase sempre esquerda → direita).
  • Ordem geral: parênteses → unários e casting → * / % → + - → comparações → == != → && → || → ternário → atribuição.
  • "a" + 1 + 2 = a12; 1 + 2 + "a" = 3a: o + soma até aparecer um texto e depois só cola.
  • Para somar dentro de um texto ou comparar dentro de um texto, parênteses: "Total: " + (a + b).
  • Na dúvida, parênteses. Eles não custam nada e deixam a intenção clara.