O Operador Modulo em Java
1. Visão geral
Neste breve tutorial, vamos mostrar o que é o operador módulo e como podemos usá-lo com Java para alguns casos de uso comuns.
2. O operador do módulo
Vamos começar com as deficiências da divisão simples em Java.
Se os operandos em ambos os lados do operador de divisão têm tipoint, o resultado da operação é outroint:
@Test
public void whenIntegerDivision_thenLosesRemainder() {
assertThat(11 / 4).isEqualTo(2);
}
A mesma divisão nos dá um resultado diferente quando pelo menos um dos operandos é do tipofloat oudouble:
@Test
public void whenDoubleDivision_thenKeepsRemainder() {
assertThat(11 / 4.0).isEqualTo(2.75);
}
Podemos observar que perdemos o restante de uma operação de divisão ao dividir números inteiros.
O operador módulo nos fornece exatamente esse restante:
@Test
public void whenModulo_thenReturnsRemainder() {
assertThat(11 % 4).isEqualTo(3);
}
O resto é o que resta depois de dividir 11 (o dividendo) por 4 (o divisor) - neste caso, 3.
Devido à mesma razão que uma divisão por zero não é possível, não é possível usar o operador módulo quando o argumento do lado direito é zero.
Tanto a divisão quanto a operação de módulo lançam umArithmeticException quando estamos tentando usar zero como o operando do lado direito:
@Test(expected = ArithmeticException.class)
public void whenDivisionByZero_thenArithmeticException() {
double result = 1 / 0;
}
@Test(expected = ArithmeticException.class)
public void whenModuloByZero_thenArithmeticException() {
double result = 1 % 0;
}
3. Casos de uso comuns
O caso de uso mais comum para o operador módulo é descobrir se um determinado número é ímpar ou par.
Se o resultado da operação do módulo entre qualquer número e dois for igual a um, é um número ímpar:
@Test
public void whenDivisorIsOddAndModulusIs2_thenResultIs1() {
assertThat(3 % 2).isEqualTo(1);
}
Por outro lado, se o resultado for zero (ou seja, não há resto), é um número par:
@Test
public void whenDivisorIsEvenAndModulusIs2_thenResultIs0() {
assertThat(4 % 2).isEqualTo(0);
}
Outro bom uso da operação de módulo é controlar o índice do próximo ponto livre em uma matriz circular.
Em uma implementação simples de uma fila circular para valores deint, os elementos são mantidos em uma matriz de tamanho fixo.
Sempre que queremos enviar um elemento para nossa fila circular, apenas calculamos a próxima posição livre calculando o módulo do número de itens que já inserimos mais 1 e a capacidade da fila:
@Test
public void whenItemsIsAddedToCircularQueue_thenNoArrayIndexOutOfBounds() {
int QUEUE_CAPACITY= 10;
int[] circularQueue = new int[QUEUE_CAPACITY];
int itemsInserted = 0;
for (int value = 0; value < 1000; value++) {
int writeIndex = ++itemsInserted % QUEUE_CAPACITY;
circularQueue[writeIndex] = value;
}
}
Usando o operador de módulo evitamos quewriteIndex saia dos limites da matriz, portanto, nunca obteremos umArrayIndexOutOfBoundsException.
No entanto, assim que inserirmos mais deQUEUE_CAPACITY itens, o próximo item substituirá o primeiro.
4. Conclusão
O operador módulo é usado para calcular o restante de uma divisão inteira que, de outra forma, seria perdida.
É útil fazer coisas simples, como descobrir se um determinado número é par ou ímpar, bem como tarefas mais complexas, como rastrear a próxima posição de escrita em uma matriz circular.
O código de exemplo está disponível emGitHub repository.