1. 概述
这篇快速入门教程中,我们将了解 Java 中的取模运算符(modulo operator)是什么,以及它在一些常见场景中的用法。
2. 取模运算符
我们先来看看 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。
和除法一样,如果右边的操作数为 0,取模也会抛出异常:
@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. 取模运算符的应用场景
取模运算符有很多实用场景。下面我们来看几个常见的用途。
⚠️ 注意:负数取模可能会得到负余数,这点要特别小心。
3.1. 常见应用场景
✅ 最常见的用途之一是判断一个数是奇数还是偶数。
任何数字对 2 取模的结果如果是 1,说明它是奇数:
@Test
public void whenDivisorIsOddAndModulusIs2_thenResultIs1() {
assertThat(3 % 2).isEqualTo(1);
}
如果是 0,说明是偶数:
@Test
public void whenDivisorIsEvenAndModulusIs2_thenResultIs0() {
assertThat(4 % 2).isEqualTo(0);
}
✅ 另一个典型应用是在循环数组中计算下一个可写入位置。
比如实现一个简单的循环队列(Circular Queue),元素存储在一个固定大小的数组中。
每次插入元素时,我们可以通过取模运算来计算下一个写入位置:
@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
,新元素会覆盖旧数据。
3.2. 负数取模问题
⚠️ 当被除数是负数时,Java 的取模结果也可能是负数:
@Test
public void whenDividendIsNegativeAndModulusIs2_thenResultIsNegative() {
assertEquals(-1, -9 % 2);
}
这可能不符合预期。我们可以手动调整为正数:
@Test
public void whenDividendIsNegativeAndRemainderIsCheckedForNegativeValue_thenResultIsPositive() {
int remainder = -9 % 2;
if (remainder < 0) {
remainder += 2;
}
assertEquals(1, remainder);
}
这里我们检查余数是否小于 0,如果是,则加上除数使其变为正数。
✅ 更优雅的做法是使用 Math.floorMod()
方法:
@Test
public void whenDividendIsNegativeAndUsesMathClass_thenResultIsPositive() {
int remainder = Math.floorMod(-9, 2);
assertEquals(1, remainder);
}
该方法会自动处理负数情况,直接返回正确的正余数。
4. 总结
本文介绍了 Java 中的取模运算符 %
,它用于获取整数除法的余数。
它可以用来做基础判断(如奇偶性),也可以用于更复杂的结构(如循环队列索引计算)。
虽然功能简单,但在实际开发中非常有用,尤其是在需要周期性行为或状态控制的场景下。
一如既往,示例代码可以在 GitHub 仓库 找到。