Рубрики
Без рубрики

Оператор по модулю в Java

Узнайте о вариантах использования оператора по модулю в Java

Автор оригинала: Tom Hombergs.

1. Обзор

В этом коротком уроке мы покажем, что такое оператор по модулю и как мы можем использовать его с Java для некоторых распространенных случаев использования.

2. Оператор по модулю

Давайте начнем с недостатков простого разделения в Java.

Если операнды с обеих сторон оператора деления имеют тип инт , результатом операции является другое инт:

@Test
public void whenIntegerDivision_thenLosesRemainder() {
    assertThat(11 / 4).isEqualTo(2);
}

То же самое деление дает нам другой результат, когда по крайней мере один из операндов имеет тип float или double:

@Test
public void whenDoubleDivision_thenKeepsRemainder() {
    assertThat(11 / 4.0).isEqualTo(2.75);
}

Можно заметить, что при делении целых чисел мы теряем остаток операции деления.

Оператор по модулю дает нам именно этот остаток:

@Test
public void whenModulo_thenReturnsRemainder() {
    assertThat(11 % 4).isEqualTo(3);
}

Остаток – это то, что остается после деления 11 (дивиденда) на 4 (делителя) – в данном случае 3.

По той же причине, по которой деление на ноль невозможно, невозможно использовать оператор по модулю, когда аргумент правой стороны равен нулю.

Как деление, так и операция по модулю вызывают исключение ArithmeticException , когда мы пытаемся использовать ноль в качестве правого операнда:

@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. Общие Случаи Использования

Наиболее распространенный случай использования оператора по модулю-это выяснить, является ли данное число нечетным или четным.

Если результат операции по модулю между любым числом и двумя равен единице, это нечетное число:

@Test
public void whenDivisorIsOddAndModulusIs2_thenResultIs1() {
    assertThat(3 % 2).isEqualTo(1);
}

С другой стороны, если результат равен нулю (то есть остатка нет), то это четное число:

@Test
public void whenDivisorIsEvenAndModulusIs2_thenResultIs0() {
    assertThat(4 % 2).isEqualTo(0);
}

Еще одним хорошим использованием операции по модулю является отслеживание индекса следующего свободного места в круговом массиве.

В простой реализации циклической очереди для значений int элементы хранятся в массиве фиксированного размера.

Каждый раз, когда мы хотим переместить элемент в нашу круговую очередь, мы просто вычисляем следующую свободную позицию, вычисляя модуль числа элементов, которые мы уже вставили, плюс 1 и емкость очереди:

@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;
    }
}

Используя оператор по модулю, мы предотвращаем выпадение индекса записи за пределы массива, поэтому мы никогда не получим исключение ArrayIndexOutOfBoundsException .

Однако, как только мы вставим больше, чем QUEUE_CAPACITY элементов, следующий элемент перезапишет первый.

4. Заключение

Оператор по модулю используется для вычисления остатка от целочисленного деления, которое в противном случае было потеряно.

Полезно делать простые вещи, такие как выяснение, является ли данное число четным или нечетным, а также более сложные задачи, такие как отслеживание следующей позиции записи в круговом массиве.

Пример кода доступен в репозитории GitHub .