Der Modulo-Operator in Java

1. Übersicht

In diesem kurzen Tutorial zeigen wir, was der Modulo-Operator ist und wie wir ihn mit Java für einige gängige Anwendungsfälle verwenden können.

2. Der Modulo-Operator

Beginnen wir mit den Mängeln der einfachen Teilung in Java.

Wenn die Operanden auf beiden Seiten des Divisionsoperators den Typ int haben , ist das Ergebnis der Operation ein anderes int:

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

Dieselbe Division führt zu einem anderen Ergebnis, wenn mindestens einer der Operanden den Typ float oder double hat:

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

Wir können beobachten, dass wir den Rest einer Divisionsoperation verlieren, wenn wir ganze Zahlen teilen.

Der Modulo-Operator gibt uns genau diesen Rest:

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

Der Rest bleibt nach der Division von 11 (Dividende) durch 4 (Divisor) - in diesem Fall 3.

Aus dem gleichen Grund ist eine Division durch Null nicht möglich. Es ist nicht möglich, den Modulo-Operator zu verwenden, wenn das Argument auf der rechten Seite Null ist.

Sowohl die Division als auch die Modulo-Operation lösen eine ArithmeticException aus, wenn wir versuchen, Null als Operanden auf der rechten Seite zu verwenden:

@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. Häufige Anwendungsfälle

Der häufigste Anwendungsfall für den Modulo-Operator besteht darin, herauszufinden, ob eine bestimmte Zahl ungerade oder gerade ist.

Wenn das Ergebnis der Modulo-Operation zwischen einer beliebigen Zahl und zwei gleich eins ist, ist es eine ungerade Zahl:

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

Wenn das Ergebnis dagegen Null ist (dh es gibt keinen Rest), ist es eine gerade Zahl:

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

Eine weitere gute Verwendung der Modulo-Operation besteht darin, den Index des nächsten freien Punkts in einer kreisförmigen Anordnung zu verfolgen.

In einer einfachen Implementierung einer kreisförmigen Warteschlange für int- Werte werden die Elemente in einem Array fester Größe gehalten.

Jedes Mal, wenn wir ein Element in unsere kreisförmige Warteschlange verschieben möchten, berechnen wir einfach die nächste freie Position, indem wir das Modulo aus der Anzahl der bereits eingefügten Elemente plus 1 und der Warteschlangenkapazität berechnen:

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

Mit dem Modulo-Operator verhindern wir, dass writeIndex aus den Grenzen des Arrays herausfällt . Daher erhalten wir niemals eine ArrayIndexOutOfBoundsException .

Sobald wir jedoch mehr als QUEUE_CAPACITY- Elemente einfügen , überschreibt das nächste Element das erste.

4. Fazit

Der Modulo-Operator wird verwendet, um den Rest einer ganzzahligen Division zu berechnen, die sonst verloren gegangen wäre.

Es ist nützlich, einfache Dinge zu tun, wie herauszufinden, ob eine bestimmte Zahl gerade oder ungerade ist, sowie komplexere Aufgaben wie das Verfolgen der nächsten Schreibposition in einem kreisförmigen Array.

Der Beispielcode ist im GitHub-Repository verfügbar.