Java Operadores de Atribuição
O operador de atribuição = guarda um valor numa variável; você o usa desde a aula de Variáveis. Mas muitas vezes queremos atualizar o valor que já está lá: somar ao saldo, descontar do estoque, dobrar a pontuação. Para isso o Java tem os operadores compostos, como +=. Eles são atalhos, mas escondem um detalhe importante que esta aula mostra com cuidado.
- Como o
=funciona por dentro (direita primeiro, depois guarda). - Os operadores
+=,-=,*=,/=e%=, inclusive comString. - O casting escondido dos compostos: por que
b += 1compila combyteeb = b + 1não. - As armadilhas
=+eif (x = 5).
Relembrando o =
O = é uma ordem: "calcule o lado direito e guarde o resultado na variável do lado esquerdo". Leia sempre como "recebe".
- saldo
- A variável que vai receber o valor. Precisa ser uma variável: não dá para escrever
10 = saldo. - =
- Recebe.
- saldo + 50
- A expressão, calculada primeiro, com o valor atual de
saldo. - ;
- Fim da instrução.
Em saldo = saldo + 50;, o Java lê o saldo atual, soma 50 e guarda o resultado de volta em saldo. O valor antigo é substituído. Esse padrão, "pegar o valor atual, fazer uma conta e guardar de volta", é tão comum que ganhou atalhos.
Os operadores compostos
Um operador composto junta uma operação aritmética com o =. saldo += 50 quer dizer exatamente "saldo recebe saldo mais 50". Imagine a conta bancária da Ana ao longo de um dia:
public class Main {
public static void main(String[] args) {
double saldo = 100.0;
System.out.println(saldo);
saldo += 50;
System.out.println(saldo);
saldo -= 30;
System.out.println(saldo);
saldo *= 2;
System.out.println(saldo);
saldo /= 4;
System.out.println(saldo);
int pontos = 17;
pontos %= 5;
System.out.println(pontos);
}
}
$ javac Main.java && java Main 100.0 150.0 « += 50: depósito 120.0 « -= 30: saque 240.0 « *= 2: dobrou 60.0 « /= 4: dividiu por 4 2 « 17 %= 5: ficou o resto, 2
| Operador | Exemplo | Equivale a | Lê-se |
|---|---|---|---|
= | x = 5 | — | x recebe 5 |
+= | x += 5 | x = x + 5 | some 5 a x |
-= | x -= 5 | x = x - 5 | subtraia 5 de x |
*= | x *= 5 | x = x * 5 | multiplique x por 5 |
/= | x /= 5 | x = x / 5 | divida x por 5 |
%= | x %= 5 | x = x % 5 | x fica com o resto da divisão por 5 |
As mesmas regras dos Operadores Aritméticos valem aqui: com int, n /= 4 faz divisão inteira (6 /= 4 deixa 1), e /= 0 lança ArithmeticException. Para somar ou subtrair exatamente 1, prefira x++ e x--.
O lado direito é calculado inteiro, antes
Em x *= 2 + 3, o Java calcula todo o lado direito (2 + 3 = 5) e só depois multiplica: o resultado é x = x * (2 + 3), e não x = x * 2 + 3. Com x valendo 10, dá 50, como mostra o próximo programa.
Com String: += acrescenta texto
Como o + cola textos, o += acrescenta texto ao final de uma String. Os outros compostos não funcionam com texto.
public class Main {
public static void main(String[] args) {
String mensagem = "Olá";
mensagem += ", Ana";
mensagem += "!";
System.out.println(mensagem);
int total = 10;
total += 2 * 3;
System.out.println(total);
int x = 10;
x *= 2 + 3;
System.out.println(x);
int a, b, c;
a = b = c = 7;
System.out.println(a + " " + b + " " + c);
}
}
$ javac Main.java && java Main Olá, Ana! 16 « total += 2 * 3: 10 + 6 50 « x *= 2 + 3: 10 * 5, não 10 * 2 + 3 7 7 7 « atribuição em cadeia
A última linha mostra a atribuição em cadeia: a = b = c = 7 é resolvido da direita para a esquerda. Primeiro c recebe 7; o resultado dessa atribuição (o próprio 7) vai para b, e depois para a. Isso funciona porque, em Java, uma atribuição também produz um valor: o valor guardado. É por isso que System.out.println(x += 5); compila e mostra o novo valor de x. Funciona, mas evite: atribuir e usar na mesma linha confunde quem lê.
Missão: o carrinho da Ana tem três produtos. Use += para somar cada preço ao total (uma linha por produto), até o programa mostrar Total: 37.5.
public class Main {
public static void main(String[] args) {
double total = 0;
double arroz = 22.90;
double feijao = 8.60;
double cafe = 6.00;
// some os três preços ao total com +=
System.out.println("Total: " + total);
}
}
public class Main {
public static void main(String[] args) {
double total = 0;
double arroz = 22.90;
double feijao = 8.60;
double cafe = 6.00;
total += arroz;
total += feijao;
total += cafe;
System.out.println("Total: " + total);
}
}
O casting escondido do +=
Até aqui, x += 5 e x = x + 5 pareceram idênticos. Quase. Veja com uma variável byte:
public class Main {
public static void main(String[] args) {
byte b = 10;
b += 1;
System.out.println(b);
b = b + 1;
}
}
$ javac Main.java
Main.java:6: error: incompatible types: possible lossy conversion from int to byte
b = b + 1;
^
1 error
A linha 4 (b += 1) passou; a linha 6 (b = b + 1) não. Por quê?
b + 1é uma conta, e contas combytesão feitas emint(a promoção de Conversão de Tipos). Guardar umintnumbyteexige casting. Daí o erro.- Os operadores compostos têm um casting embutido. Pela especificação do Java,
b += 1equivale ab = (byte) (b + 1): o resultado é convertido de volta para o tipo da variável, sem você pedir.
Isso é conveniente com byte, short e char (você já viu letra += 2 avançar letras em char e boolean). Mas o mesmo casting escondido também corta valores sem avisar:
public class Main {
public static void main(String[] args) {
int estoque = 10;
estoque += 3.7;
System.out.println(estoque);
int preco = 10;
preco *= 1.5;
System.out.println(preco);
byte b = 120;
b += 10;
System.out.println(b);
char letra = 'A';
letra += 2;
System.out.println(letra);
}
}
$ javac Main.java && java Main 13 « 10 + 3.7 = 13.7, cortado para 13 sem erro nenhum! 15 « 10 * 1.5 = 15.0, que vira 15 -126 « 120 + 10 = 130 não cabe num byte: deu a volta C « 'A' + 2 continua char
| Código | Compila? | Por quê |
|---|---|---|
estoque = estoque + 3.7; (int) | Não: possible lossy conversion from double to int | Sem casting automático |
estoque += 3.7; (int) | Sim, e guarda 13 | Equivale a estoque = (int) (estoque + 3.7) |
b = b + 1; (byte) | Não: possible lossy conversion from int to byte | b + 1 é int |
b += 1; (byte) | Sim | Equivale a b = (byte) (b + 1) |
+= não protege você
Com =, o javac recusa conversões com perda. Com +=, *= e companhia, ele aceita e corta em silêncio. Se o valor da direita pode ter casas decimais, a variável provavelmente deveria ser double.
Missão: o nível do jogador é um byte e a linha que sobe de nível não compila. Troque-a por um operador composto, sem casting, para o programa mostrar Nível 6.
public class Main {
public static void main(String[] args) {
byte nivel = 5;
nivel = nivel + 1;
System.out.println("Nível " + nivel);
}
}
public class Main {
public static void main(String[] args) {
byte nivel = 5;
nivel += 1;
System.out.println("Nível " + nivel);
}
}
Quando dá errado
=+ no lugar de +=: compila e faz outra coisa
public class Main {
public static void main(String[] args) {
int pontos = 10;
pontos =+ 5;
System.out.println(pontos);
pontos =- 3;
System.out.println(pontos);
}
}
$ javac Main.java && java Main 5 « esperava 15 -3 « esperava 2
O que aconteceu: o Java leu pontos =+ 5 como pontos = +5: atribuição comum de "mais cinco" (o + unário). E =- 3 virou = -3. Nenhum erro, nenhum aviso: só o valor errado.
Como consertar: nos compostos, o sinal da operação vem antes do =: +=, -=. Lembre: "mais-igual".
if (idade = 18): "int cannot be converted to boolean"
public class Main {
public static void main(String[] args) {
int idade = 18;
if (idade = 18) {
System.out.println("Maior de idade");
}
}
}
$ javac Main.java
Main.java:4: error: incompatible types: int cannot be converted to boolean
if (idade = 18) {
^
1 error
O que quer dizer: = atribui; não compara. idade = 18 guarda 18 e produz o valor 18, um int, e o if precisa de um boolean. Em C, esse erro compila e o programa faz a coisa errada; em Java, o tipo boolean pega o erro na hora (veja char e boolean).
Como consertar: para comparar, use dois sinais: if (idade == 18). Veja Operadores de Comparação.
+= numa variável sem valor: "might not have been initialized"
$ javac Main.java
Main.java:4: error: variable total might not have been initialized
total += 5;
^
1 error
O que quer dizer: total += 5 precisa ler o valor atual de total, e ela foi só declarada (int total;).
Como consertar: comece de um valor: int total = 0;. Todo acumulador começa em zero (ou em "", para texto).
x + = 2 dá "illegal start of expression"
$ javac Main.java
Main.java:4: error: illegal start of expression
x + = 2;
^
1 error
O que quer dizer: += é um operador de dois caracteres; com espaço no meio, viram dois símbolos soltos (+ e =) e o Java não entende.
Como consertar: escreva junto: x += 2;.
10 = estoque dá "unexpected type"
$ javac Main.java
Main.java:4: error: unexpected type
10 = estoque;
^
required: variable
found: value
1 error
O que quer dizer: à esquerda do = precisa haver uma variável (required: variable), e foi encontrado um valor (found: value). Não dá para guardar algo "dentro do 10".
Como consertar: a variável que recebe fica sempre à esquerda: estoque = 10;.
Referência
| Operador | Equivale a | Exemplo (x = 10) → x |
|---|---|---|
x = v | — | x = 3 → 3 |
x += v | x = (tipo de x) (x + v) | x += 3 → 13 |
x -= v | x = (tipo de x) (x - v) | x -= 3 → 7 |
x *= v | x = (tipo de x) (x * v) | x *= 3 → 30 |
x /= v | x = (tipo de x) (x / v) | x /= 3 → 3 (inteiro) |
x %= v | x = (tipo de x) (x % v) | x %= 3 → 1 |
s += "txt" | s = s + "txt" | Acrescenta texto a uma String |
a = b = v | b = v; a = b; | Da direita para a esquerda |
Existem ainda os compostos de operadores de bits: &=, |=, ^=, <<=, >>= e >>>=. Eles seguem a mesma lógica (x &= y é x = x & y); o &= e o |= com boolean aparecem em Operadores Lógicos.
Exercícios
1. Depósito
Complete com o operador composto que soma 200 ao saldo:
2. Metade
Complete para dividir bolo por 2, guardando o resultado nela mesma:
3. Quanto vale?
Depois de int x = 4; x *= 3 + 1;, quanto vale x?
4. Com byte b = 5;, qual linha compila?
5. Depois de int n = 10; n =+ 3;, quanto vale n?
6. Depois de int estoque = 10; estoque += 2.9;, quanto vale estoque?
Resumo
=calcula a direita e guarda na esquerda; a esquerda precisa ser uma variável.+=,-=,*=,/=e%=atualizam a variável usando o valor atual:saldo += 50ésaldo = saldo + 50. Todo o lado direito é calculado antes.- Com
String,+=acrescenta texto. - Os compostos têm casting embutido:
byte b += 1compila (eb = b + 1não), masint x += 3.7corta para inteiro sem avisar. - Cuidado com
=+(vira "recebe mais") e com=no lugar de==numif.