Java Operadores Aritméticos

Programas fazem contas o tempo todo: o total de uma compra, a média da turma, quantas caixas cabem num caminhão. Os operadores aritméticos são os símbolos dessas contas. Quatro deles você conhece da escola; os outros (%, ++ e --) são novidade e muito usados. Nesta aula você vai ver cada um, com atenção especial à divisão, que tem as maiores surpresas.

Você vai aprender
  • Os operadores +, -, *, / e %.
  • A diferença entre divisão inteira e decimal.
  • Para que serve o resto da divisão (%), inclusive com negativos.
  • O incremento e o decremento (++ e --), nas formas "pré" e "pós".
  • O que acontece ao dividir por zero.

Os cinco operadores

Um operador é um símbolo que faz uma operação com valores; os valores são os operandos. Em 17 + 5, o operador é + e os operandos são 17 e 5. A Ana tem 17 maçãs para dividir entre 5 pessoas:

public class Main {
    public static void main(String[] args) {
        int macas = 17;
        int pessoas = 5;
        System.out.println(macas + pessoas);
        System.out.println(macas - pessoas);
        System.out.println(macas * pessoas);
        System.out.println(macas / pessoas);
        System.out.println(macas % pessoas);
    }
}
$ javac Main.java && java Main
22
12
85
3                  « 17 / 5: cada pessoa recebe 3 maçãs inteiras
2                  « 17 % 5: sobram 2 maçãs
OperadorNomeExemploResultado
+Soma (adição)17 + 522
-Subtração17 - 512
*Multiplicação (asterisco, não x)17 * 585
/Divisão (barra, não ÷)17 / 53 (inteiros!)
%Resto da divisão (módulo)17 % 52

Com String, o + tem outro papel: colar textos (Concatenação). Os outros operadores aritméticos não funcionam com texto. E não existe operador de potência: 2 ^ 3 compila, mas é outra coisa (dá 1); para 2³, use Math.pow(2, 3), que dá 8.0 (Math).

Brinque com o código: mude a quantidade de maçãs e de pessoas. Tente valores em que a divisão é exata (20 e 5) e valores em que sobra muito (19 e 5).

public class Main {
    public static void main(String[] args) {
        int macas = 17;
        int pessoas = 5;
        System.out.println("Cada pessoa recebe: " + macas / pessoas);
        System.out.println("Sobram: " + macas % pessoas);
    }
}

Divisão inteira × divisão decimal

A regra mais importante desta aula: quando os dois operandos são inteiros, a divisão é inteira. O resultado é um inteiro e a parte decimal é jogada fora (não é arredondada). Basta um dos dois ser decimal para a divisão ser decimal:

public class Main {
    public static void main(String[] args) {
        System.out.println(7 / 2);
        System.out.println(7.0 / 2);
        System.out.println(7 / 2.0);
        System.out.println(7.0 / 2.0);
        System.out.println(1 / 3);
        System.out.println(2 / 3);
        System.out.println(-7 / 2);
        int soma = 15;
        int n = 2;
        System.out.println(soma / n);
        System.out.println((double) soma / n);
        System.out.println(soma / (double) n);
        System.out.println((double) (soma / n));
        System.out.println(soma * 1.0 / n);
    }
}
$ javac Main.java && java Main
3                  « 7 / 2: inteiros, o .5 some
3.5
3.5
3.5
0                  « 1 / 3 = 0,333... → 0
0                  « 2 / 3 = 0,666... → 0 (cortou, não arredondou para 1)
-3                 « corta em direção ao zero: -3,5 → -3
7                  « soma / n com duas variáveis int
7.5                « (double) soma / n
7.5                « soma / (double) n
7.0                « (double) (soma / n): tarde demais, a divisão já foi inteira
7.5                « soma * 1.0 / n: o truque de multiplicar por 1.0

Por que o Java faz assim? Porque é o que a divisão inteira significa: "quantas vezes o 2 cabe inteiro no 7?" Três vezes. Isso é útil (distribuir maçãs, calcular páginas, converter segundos em minutos), mas é a causa número um de médias erradas.

Para fazer uma divisão decimal com variáveis intResultado
(double) soma / nRecomendado: o casting converte soma antes de dividir.
soma / (double) nTambém funciona.
soma * 1.0 / nFunciona; é um truque comum, mas menos claro.
(double) (soma / n)Errado: divide primeiro (inteiro) e converte depois.

Os detalhes do casting e da "promoção" de tipos estão em Conversão de Tipos.


O resto da divisão: %

O % não tem nada a ver com porcentagem: ele dá o resto da divisão inteira, aquele número que sobrava na "conta de dividir" da escola. Em inglês o nome é modulo, e por isso muita gente o chama de "módulo".

public class Main {
    public static void main(String[] args) {
        System.out.println(10 % 3);
        System.out.println(9 % 3);
        System.out.println(2 % 5);
        System.out.println(-7 % 3);
        System.out.println(7 % -3);
        System.out.println(-7 % -3);
        System.out.println(Math.floorMod(-7, 3));
        System.out.println(7.5 % 2);
        System.out.println(14 % 2);
        System.out.println(15 % 2);
        int segundos = 125;
        System.out.println(segundos / 60 + " min e " + segundos % 60 + " s");
        int numero = 4827;
        System.out.println(numero % 10);
    }
}
$ javac Main.java && java Main
1                  « 10 = 3 × 3 + 1
0                  « 9 é divisível por 3: resto zero
2                  « 2 = 5 × 0 + 2 (o menor dividido pelo maior sobra inteiro)
-1                 « o sinal do resto é o sinal do PRIMEIRO número
1
-1
2                  « Math.floorMod: resto sempre com o sinal do divisor
1.5                « também funciona com double
0                  « 14 é par
1                  « 15 é ímpar
2 min e 5 s
7                  « o último dígito

Para que serve o resto

UsoComoExemplo
Saber se é par ou ímparn % 2 dá 0 (par) ou não (ímpar)14 % 2 → 0
Saber se é divisíveln % d == 09 % 3 → 0
Converter unidades/ para a parte inteira, % para o que sobra125 s → 2 min e 5 s
Pegar o último dígiton % 104827 % 10 → 7
Dar a volta num ciclo (dias da semana, relógio)(hora + 5) % 2422h + 5h → 3

Resto com números negativos

Em Java, o resultado de % tem sempre o sinal do primeiro operando: -7 % 3 dá -1, não 2. Isso vem da divisão inteira, que corta em direção ao zero (-7 / 3 = -2, e -2 × 3 + (-1) = -7). Se você precisa de um resto sempre positivo (por exemplo, para "voltar" dias da semana), use Math.floorMod(-7, 3), que dá 2.

Teste de ímpar com negativos

n % 2 == 1 falha para ímpares negativos, porque -3 % 2 dá -1. O teste seguro é n % 2 != 0 ("o resto não é zero"). O == e o != estão em Operadores de Comparação.

Missão: a música tem 200 segundos. Complete a linha para mostrar 3 min e 20 s, usando / para os minutos e % para os segundos que sobram.

public class Main {
    public static void main(String[] args) {
        int duracao = 200;
        int minutos = 0;
        int segundos = 0;
        System.out.println(minutos + " min e " + segundos + " s");
    }
}
public class Main {
    public static void main(String[] args) {
        int duracao = 200;
        int minutos = duracao / 60;
        int segundos = duracao % 60;
        System.out.println(minutos + " min e " + segundos + " s");
    }
}

Incremento e decremento: ++ e --

Somar 1 ou subtrair 1 de uma variável é tão comum (contar alunos, avançar uma senha na fila, contar voltas de um for) que o Java tem operadores só para isso:

OperadorNomeEquivale a
a++ ou ++aIncremento ("aumentar")a = a + 1
a-- ou --aDecremento ("diminuir")a = a - 1

Numa linha sozinha, a++; e ++a; fazem exatamente a mesma coisa. A diferença só aparece quando o operador é usado dentro de outra expressão (numa atribuição, num println):

  • Pós-incremento x++ (o ++ depois): usa o valor atual e depois soma 1.
  • Pré-incremento ++x (o ++ antes): primeiro soma 1 e depois usa o valor novo.
public class Main {
    public static void main(String[] args) {
        int a = 5;
        a++;
        System.out.println(a);
        a--;
        System.out.println(a);
        ++a;
        System.out.println(a);
        int x = 5;
        int y = x++;
        System.out.println("x = " + x + ", y = " + y);
        int p = 5;
        int q = ++p;
        System.out.println("p = " + p + ", q = " + q);
        int c = 10;
        System.out.println(c++);
        System.out.println(c);
        System.out.println(++c);
        System.out.println(c--);
        System.out.println(c);
    }
}
$ javac Main.java && java Main
6                  « a++ sozinho: 5 → 6
5                  « a--: 6 → 5
6                  « ++a sozinho: igual ao a++
x = 6, y = 5       « y = x++: y recebeu o valor ANTIGO (5), depois x virou 6
p = 6, q = 6       « q = ++p: p virou 6 ANTES, e q recebeu 6
10                 « println(c++): mostra 10, depois c vira 11
11
12                 « println(++c): c vira 12, depois mostra
12                 « println(c--): mostra 12, depois c vira 11
11

Uma forma de lembrar: leia da esquerda para a direita. Em x++, você "vê" o x primeiro (usa o valor) e o ++ depois (soma). Em ++x, o ++ vem primeiro.

Deixe o ++ sozinho na linha

Misturar ++ com outras contas (y = x++ + ++x) é um ótimo exercício de prova e um péssimo código: ninguém entende de primeira. No dia a dia, escreva contador++; numa linha própria e use o valor na linha seguinte. A armadilha mais famosa: x = x++; não muda x (o x recebe o valor antigo de volta); um programa com int x = 5; x = x++; mostra 5.

Missão: na fila do banco, a primeira senha chamada deve ser a 1. Mas o programa mostra Próxima senha: 0, porque usa o pós-incremento. Troque para o pré-incremento para que ele mostre Próxima senha: 1.

public class Main {
    public static void main(String[] args) {
        int fila = 0;
        System.out.println("Próxima senha: " + fila++);
    }
}
public class Main {
    public static void main(String[] args) {
        int fila = 0;
        System.out.println("Próxima senha: " + ++fila);
    }
}

Sinal: -x e +x

O - também funciona com um único operando, para trocar o sinal: se temperatura vale 5, -temperatura vale -5. O + unário existe, mas não faz nada. Esses operadores de um operando só se chamam unários (o ++ e o -- também são). 3 - -2 dá 5: menos com menos.


Divisão por zero

O que acontece se a Ana dividir 10 bolos entre 0 convidados? Depende do tipo:

public class Main {
    public static void main(String[] args) {
        int bolos = 10;
        int convidados = 0;
        System.out.println(10.0 / 0);
        System.out.println(bolos / convidados);
    }
}
$ javac Main.java && java Main
Infinity
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Main.main(Main.java:6)
ContaO que acontece
Inteiro / 0 ou inteiro % 0O programa para com ArithmeticException: / by zero ("exceção aritmética: divisão por zero"), apontando a linha (Main.java:6).
double / 0Não para: o resultado é Infinity, -Infinity ou NaN (0.0 / 0). Veja double e float.

Repare que o programa compilou: o javac não tem como saber que convidados vai valer zero. Mesmo System.out.println(10 / 0);, com o zero escrito no código, compila e só falha ao rodar. Divisões cujo divisor pode ser zero devem ser protegidas com um if (if (convidados != 0)) ou tratadas com try e catch.


Quando dá errado

"ArithmeticException: / by zero"
$ javac Main.java && java Main
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Main.main(Main.java:3)

O que quer dizer: uma divisão (ou resto) de inteiros teve divisor zero na linha indicada. A mesma mensagem aparece para %: 10 % 0 também diz / by zero.

Como consertar: descubra por que o divisor chegou a zero (uma lista vazia? um valor que o usuário digitou?) e confira antes de dividir.

A média saiu sem casas decimais

O que aconteceu: divisão inteira. soma / quantidade com duas variáveis int descarta a parte decimal, mesmo guardando num double.

Como consertar: (double) soma / quantidade.

++ num valor: "unexpected type … required: variable, found: value"
$ javac Main.java
Main.java:5: error: unexpected type
        5++;
        ^
  required: variable
  found:    value
1 error

O que quer dizer: "tipo inesperado: era preciso uma variável, foi encontrado um valor". O ++ guarda o resultado de volta, então só funciona em variáveis; não dá para "incrementar o 5". O mesmo vale para (a + b)++.

Como consertar: use ++ só em variáveis. Para obter o valor seguinte sem guardar, escreva 5 + 1.

"bad operand types for binary operator '-'"
$ javac Main.java
Main.java:4: error: bad operand types for binary operator '-'
        String b = a - "a";
                     ^
  first type:  String
  second type: String
1 error

O que quer dizer: "tipos de operando inválidos para o operador binário '-'". Com String, só o + funciona (para colar). first type e second type dizem os tipos dos dois lados.

Como consertar: se os textos guardam números, converta antes com Integer.parseInt (Conversão de Tipos). Para manipular texto, use os Métodos de String.

"Total: " + 3 + 2 mostrou Total: 32

O que aconteceu: depois de um texto, o + cola em vez de somar: primeiro "Total: " + 3 vira "Total: 3", depois cola o 2.

Como consertar: parênteses em volta da conta: "Total: " + (3 + 2) mostra Total: 5. Veja Precedência.


Referência

OperadorFazExemplo → resultadoCuidado
+Soma (ou cola texto)7 + 2 → 9Com String, cola
-Subtração / troca de sinal7 - 2 → 5; -x
*Multiplicação7 * 2 → 14Overflow com números grandes
/Divisão7 / 2 → 3; 7.0 / 2 → 3.5Inteiros: corta; / 0: exceção
%Resto7 % 2 → 1Sinal do primeiro operando
x++Usa, depois soma 1y = x++Só em variáveis
++xSoma 1, depois usay = ++xSó em variáveis
x-- / --xO mesmo, subtraindo 1vidas--
Math.pow(a, b)Potência (não é operador)Math.pow(2, 3) → 8.02 ^ 3 não é potência
Math.floorMod(a, b)Resto com o sinal do divisorMath.floorMod(-7, 3) → 2

Atalhos como total += preco estão em Operadores de Atribuição; a ordem em que as contas são feitas (2 + 3 * 4) está em Precedência.


Exercícios

1. Divisão inteira

Quanto vale 19 / 4 em Java?

2. O resto

Quanto vale 19 % 4?

3. Par ou ímpar

Complete a expressão que dá 0 quando n é par:

n

4. Média decimal

Complete o casting para a média de soma e n (ambos int) ter casas decimais:

double media = soma / n;

5. Depois de int x = 3; int y = x++;, quanto valem x e y?

6. O que acontece ao executar int r = 10 / 0;?

7. Quanto vale -7 % 3 em Java?


Resumo

  • + - * / são as quatro operações; % é o resto da divisão inteira.
  • Dois inteiros dão divisão inteira: 7 / 2 = 3, cortando a parte decimal. Para decimais, um dos lados deve ser double: (double) soma / n.
  • % serve para par/ímpar, divisibilidade, converter unidades e pegar o último dígito. O sinal do resto é o do primeiro número; Math.floorMod dá resto positivo.
  • x++ usa e depois soma; ++x soma e depois usa. Sozinhos na linha, são iguais.
  • Inteiro dividido por zero: ArithmeticException: / by zero. double dividido por zero: Infinity ou NaN.