Operadores aritméticos
Operadores aritméticos trabalham com números (tipos primitivos numéricos) e produzem um resultado numérico. Em Java, a escolha do tipo do resultado pode envolver promoção numérica (por exemplo, operações com int podem “subir” para long se um dos operandos for long).
+soma-subtração*multiplicação/divisão%resto (módulo)
Divisão inteira vs. divisão com ponto flutuante
Se ambos os operandos forem inteiros, a divisão é inteira (trunca a parte decimal). Para obter casas decimais, pelo menos um operando deve ser double ou float.
int a = 7; int b = 2; int divInteira = a / b; // 3 double divReal = a / 2.0; // 3.5 double divReal2 = (double) a / b; // 3.5Passo a passo prático: calculando total com desconto
Vamos calcular o total de uma compra com desconto percentual e frete fixo, cuidando para não cair em divisão inteira.
- Defina o subtotal e o desconto em porcentagem.
- Converta a porcentagem para fator decimal (
desconto / 100.0). - Calcule o valor do desconto e subtraia do subtotal.
- Some o frete.
double subtotal = 199.90; int descontoPercentual = 10; double frete = 15.00; double fatorDesconto = descontoPercentual / 100.0; // 0.10 double valorDesconto = subtotal * fatorDesconto; double total = (subtotal - valorDesconto) + frete;Operadores de incremento e decremento
Os operadores ++ e -- aumentam ou diminuem 1 unidade. Eles podem ser usados em forma prefixada ou pós-fixada, e isso muda o valor “observado” na expressão.
++x: incrementa e depois usa o valorx++: usa o valor e depois incrementa
int x = 10; int a = ++x; // x vira 11, a recebe 11 int y = 10; int b = y++; // b recebe 10, y vira 11Boa prática
Evite misturar ++/-- dentro de expressões longas. Prefira linhas separadas para reduzir ambiguidades.
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
// Menos legível: int resultado = valores[i++] + valores[i++]; // Mais legível: int primeiro = valores[i]; i++; int segundo = valores[i]; i++; int resultado = primeiro + segundo;Operadores relacionais e igualdade
Operadores relacionais comparam valores e retornam boolean.
>,>=,<,<===(igualdade)!=(diferença)
Armadilha comum: comparar Strings com ==
Para tipos por referência (como String), == compara referências (se é o mesmo objeto), não o conteúdo. Para comparar conteúdo, use equals (ou equalsIgnoreCase quando fizer sentido).
String s1 = new String("java"); String s2 = new String("java"); boolean refIgual = (s1 == s2); // false (referências diferentes) boolean conteudoIgual = s1.equals(s2); // truePasso a passo prático: comparação segura com possível null
Se uma variável pode ser null, chamar variavel.equals("x") pode lançar NullPointerException. Uma prática comum é inverter: chamar "x".equals(variavel).
- Escolha o literal como receptor de
equals. - Passe a variável possivelmente nula como argumento.
String status = null; boolean ativo = "ATIVO".equals(status); // false, sem exceçãoOperadores lógicos e curto-circuito
Operadores lógicos combinam condições booleanas.
&&(E lógico com curto-circuito)||(OU lógico com curto-circuito)!(negação)
Curto-circuito (short-circuit)
Com &&, se a primeira condição for false, a segunda não é avaliada. Com ||, se a primeira for true, a segunda não é avaliada. Isso é útil para evitar erros e reduzir custo de avaliação.
String nome = null; // Evita NullPointerException porque a segunda parte não roda se nome == null boolean valido = (nome != null) && (nome.length() >= 3);Armadilha: confundir && com & e || com |
& e | também funcionam com boolean, mas não fazem curto-circuito (avaliam ambos os lados). Isso pode causar exceções ou efeitos colaterais inesperados.
String nome = null; // Lança NullPointerException porque (nome.length() >= 3) será avaliado boolean valido = (nome != null) & (nome.length() >= 3);Operador ternário (?:)
O operador ternário escolhe entre dois valores com base em uma condição: condicao ? valorSeVerdadeiro : valorSeFalso. Ele é uma expressão (produz um valor), então é útil para atribuições.
int idade = 17; String categoria = (idade >= 18) ? "ADULTO" : "MENOR";Boa prática
Use ternário para decisões simples. Se a lógica ficar complexa (ternários aninhados, múltiplas condições), prefira if/else ou extraia para métodos com nomes descritivos.
// Pouco legível (aninhado): String faixa = idade < 12 ? "CRIANCA" : idade < 18 ? "ADOLESCENTE" : "ADULTO"; // Mais legível: String faixa; if (idade < 12) { faixa = "CRIANCA"; } else if (idade < 18) { faixa = "ADOLESCENTE"; } else { faixa = "ADULTO"; }Concatenação com + e armadilhas com números
O operador + soma números e também concatena strings. Quando uma das partes é String, o restante tende a virar concatenação, seguindo a ordem de avaliação (da esquerda para a direita).
System.out.println("Total: " + 10 + 5); // "Total: 105" System.out.println("Total: " + (10 + 5)); // "Total: 15"Passo a passo prático: montando uma mensagem sem ambiguidade
- Calcule valores numéricos antes.
- Use parênteses quando misturar números e strings.
- Prefira variáveis intermediárias com nomes claros.
int itens = 10; int bonus = 5; int totalItens = itens + bonus; String mensagem = "Itens no carrinho: " + totalItens;Operadores bitwise: noções e casos práticos simples
Operadores bitwise atuam no nível de bits de tipos inteiros (byte, short, int, long). São úteis para flags, máscaras, permissões e manipulação eficiente de estados.
&AND bit a bit|OR bit a bit^XOR bit a bit~NOT bit a bit<<shift à esquerda>>shift à direita (preserva sinal)>>>shift à direita sem sinal
Flags com máscara (caso comum)
Você pode representar permissões como bits: cada bit indica se uma permissão está ativa. Exemplo: leitura, escrita e execução.
final int PERM_LER = 1; // 001 final int PERM_ESCREVER = 2; // 010 final int PERM_EXECUTAR = 4; // 100 int permissoes = 0; // Ativar leitura e execução permissoes = permissoes | PERM_LER; permissoes = permissoes | PERM_EXECUTAR; // Testar se tem escrita boolean podeEscrever = (permissoes & PERM_ESCREVER) != 0; // Remover execução permissoes = permissoes & ~PERM_EXECUTAR;Passo a passo prático: alternar uma flag com XOR
^ (XOR) é útil para alternar um bit: se estiver ligado, desliga; se estiver desligado, liga.
- Defina a máscara do bit.
- Use
valor ^ mascarapara alternar.
final int MODO_NOTURNO = 1; // 0001 int config = 0; // modo noturno desligado config = config ^ MODO_NOTURNO; // liga config = config ^ MODO_NOTURNO; // desligaShifts: multiplicar/dividir por potências de 2 (com cuidado)
x << 1 equivale a multiplicar por 2; x >> 1 equivale a dividir por 2 (arredondando para baixo em inteiros, com particularidades para negativos). Use quando fizer sentido e a legibilidade não for prejudicada.
int x = 6; int vezes2 = x << 1; // 12 int metade = x >> 1; // 3Precedência e associatividade de operadores
Precedência define quais operações acontecem primeiro em uma expressão. Associatividade define como operadores do mesmo nível se agrupam (geralmente da esquerda para a direita). Mesmo conhecendo as regras, uma boa prática é usar parênteses para deixar a intenção explícita.
| Categoria | Exemplos | Observação |
|---|---|---|
| Unários | ++ -- ! ~ | Alta precedência |
| Multiplicativos | * / % | Antes de + - |
| Aditivos | + - | Concatenação com String entra aqui |
| Shift | << >> >>> | Após aditivos |
| Relacionais | < <= > >= | Antes de igualdade |
| Igualdade | == != | Cuidado com referências |
| Bitwise | & ^ | | Sem curto-circuito |
| Lógicos | && || | Com curto-circuito |
| Ternário | ?: | Baixa precedência |
| Atribuição | = += -= *= ... | Uma das mais baixas |
Exemplos de precedência que confundem
boolean r1 = true || false && false; // && vem antes de ||, então: true || (false && false) => true int r2 = 10 + 2 * 3; // 16 (multiplica antes) int r3 = (10 + 2) * 3; // 36Boas práticas de legibilidade em expressões
1) Use parênteses para explicitar intenção
Mesmo quando a precedência “resolve”, parênteses tornam a leitura mais rápida e reduzem bugs em manutenção.
// Menos claro: boolean ok = idade >= 18 && temDocumento || acompanhado; // Mais claro (intenção explícita): boolean ok = (idade >= 18 && temDocumento) || acompanhado;2) Prefira nomes descritivos para subexpressões
Quebre expressões longas em variáveis booleanas intermediárias. Isso melhora leitura, facilita testes e reduz duplicação.
// Difícil de ler: boolean podeFinalizar = (cliente != null) && ("ATIVO".equals(cliente.getStatus())) && (total > 0) && (!bloqueado) && (limite >= total); // Mais legível: boolean clienteExiste = (cliente != null); boolean clienteAtivo = clienteExiste && "ATIVO".equals(cliente.getStatus()); boolean totalValido = total > 0; boolean dentroDoLimite = limite >= total; boolean podeFinalizar = clienteAtivo && totalValido && !bloqueado && dentroDoLimite;3) Refatore expressões longas para métodos com nome
Quando a regra de negócio é reutilizada ou tem significado próprio, extraia para um método com nome que descreva a intenção.
// Em vez de repetir a regra em vários lugares: boolean elegivel = (idade >= 18) && (renda >= 3000) && !inadimplente; // Extraia: boolean elegivel = isElegivelParaCredito(idade, renda, inadimplente);static boolean isElegivelParaCredito(int idade, double renda, boolean inadimplente) { boolean maiorDeIdade = idade >= 18; boolean rendaMinima = renda >= 3000; return maiorDeIdade && rendaMinima && !inadimplente; }4) Evite efeitos colaterais em condições
Condições devem preferencialmente apenas verificar, não alterar estado. Isso reduz surpresas com curto-circuito e facilita depuração.
// Evite: if (usuario != null && usuario.incrementaTentativas() < 3) { ... } // Prefira: if (usuario != null) { int tentativas = usuario.incrementaTentativas(); if (tentativas < 3) { ... } }5) Use operadores compostos com parcimônia
Operadores como +=, *= são úteis e legíveis em atualizações simples. Em expressões complexas, prefira etapas intermediárias.
double total = 0; total += 19.90; total += 5.00; // claro // Se ficar complexo, quebre: double taxa = subtotal * 0.12; total = subtotal + taxa + frete;