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.
- O que são precedência e associatividade.
- A tabela de precedência dos operadores do Java.
- Por que
"a" + 1 + 2dáa12, mas1 + 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 isso2 + 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, e10 / 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.
| Ordem | Operadores | Nome | Associatividade |
|---|---|---|---|
| 1 | x++ x-- () . [] | Pós-fixos, chamada de método, acesso a membro e a array | esquerda → direita |
| 2 | ++x --x +x -x ! ~ (tipo) | Unários e casting | direita → esquerda |
| 3 | * / % | Multiplicativos | esquerda → direita |
| 4 | + - | Aditivos (e concatenação de String) | esquerda → direita |
| 5 | << >> >>> | Deslocamento de bits | esquerda → direita |
| 6 | < > <= >= instanceof | Relacionais | esquerda → direita |
| 7 | == != | Igualdade | esquerda → direita |
| 8 | & | E de bits / E sem curto-circuito | esquerda → direita |
| 9 | ^ | Ou exclusivo | esquerda → direita |
| 10 | | | Ou de bits / Ou sem curto-circuito | esquerda → direita |
| 11 | && | E lógico | esquerda → direita |
| 12 | || | Ou lógico | esquerda → direita |
| 13 | ? : | Ternário | direita → esquerda |
| 14 | = += -= *= /= %= … | Atribuição | direita → 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 + 2: dois números, soma. Resultado:3.3 + "a": um dos lados é texto, então cola. Resultado:"3a"."3a" + 1: texto com número, cola. Resultado:"3a1"."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ão | Como o Java lê | Regra |
|---|---|---|
a = b = c = 5 | a = (b = (c = 5)) | Atribuição associa da direita para a esquerda |
x += x * 2 | x = x + (x * 2) | Atribuição é a última de todas |
1 + 2 == 3 | (1 + 2) == 3 | Aritmética antes de comparação |
true || false && false | true || (false && false) | && antes de || |
!false && false | (!false) && false | Unários antes de tudo |
(double) 7 / 2 | ((double) 7) / 2 | Casting é 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 / nou(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
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 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
| Regra | Exemplo → 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 → direita | 10 / 2 * 5 → 25; "a" + 1 + 2 → a12 |
| Aritmética antes de comparação | 1 + 2 == 3 → true |
Comparação antes de && e || | x > 0 && x < 10 |
&& antes de || | true || false && false → true |
| Atribuição por último, direita → esquerda | a = 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.