Операторът Modulo в Java

1. Общ преглед

В този кратък урок ще покажем какво представлява модулният оператор и как можем да го използваме с Java за някои често използвани случаи.

2. Операторът Modulo

Нека започнем с недостатъците на простото разделяне в Java.

Ако операндите от двете страни на оператора за разделяне имат тип int , резултатът от операцията е друг int:

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

Използвайки модула оператор, ние предотвратяваме writeIndex да падне извън границите на масива, следователно никога няма да получим ArrayIndexOutOfBoundsException .

След като обаче вмъкнем повече от QUEUE_CAPACITY елемента, следващият елемент ще замени първия.

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

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

Полезно е да правите прости неща като да разберете дали дадено число е четно или нечетно, както и по-сложни задачи като проследяване на следващата позиция на запис в кръгъл масив.

Примерният код е достъпен в хранилището на GitHub.