3.2 算术、除法与余数
前置知识:表达式、赋值与求值顺序
预计时间:25 分钟
完成标志:能预测正负整数除法、余数、溢出和自增副作用
基本算术与类型
int left = 10;
int right = 3;
System.out.println(left + right); // 13
System.out.println(left - right); // 7
System.out.println(left * right); // 30
System.out.println(left / right); // 3
System.out.println(left % right); // 1byte、short 和 char 参与普通算术时通常先提升为 int。表达式还可能溢出,类型不会因结果过大自动升级。
整数除法向零截断
System.out.println(10 / 3); // 3
System.out.println(-10 / 3); // -3
System.out.println(10 / -3); // -3
System.out.println(-10 / -3); // 3“丢掉小数”只适合正数直觉;正式规则是商向零截断。
至少一个操作数为浮点类型时执行浮点除法:
System.out.println(10 / 3.0); // 3.3333333333333335
System.out.println((double) 10 / 3); // 3.3333333333333335赋给 double 不会倒推右侧运算:
double wrong = 10 / 3; // 先得 int 3,再拓宽为 3.0
double right = 10 / 3.0;整数除以零抛 ArithmeticException;浮点除以正零或负零按 IEEE 754 产生无穷或 NaN:
System.out.println(1.0 / 0.0); // Infinity
System.out.println(0.0 / 0.0); // NaN还有一个整数边界:Integer.MIN_VALUE / -1 的数学结果超出 int,Java 返回 Integer.MIN_VALUE。Math.floorDiv 也不会检测这个溢出;在 Java 17 中应单独检查这一对输入,或先把操作数转为 long 再除。
% 是余数,不是总为非负的模
Java 余数满足:
(a / b) * b + (a % b) == a这里按 Java 的整数运算规则求值,并要求除数不为零。即使 MIN_VALUE / -1 溢出,该恒等式在 Java 的回绕运算下仍成立。非零余数的符号跟被除数一致:
System.out.println(7 % 3); // 1
System.out.println(-7 % 3); // -1
System.out.println(7 % -3); // 1因此判断奇数要写:
boolean odd = value % 2 != 0;value % 2 == 1 会漏掉负奇数。
模数为正、需要落在 0..modulus-1 的循环索引时,使用:
int wrapped = Math.floorMod(index, 3);System.out.println(-1 % 3); // -1
System.out.println(Math.floorMod(-1, 3)); // 2分页也要先定义编号口径。若条目从 0 开始,index / pageSize 是页索引;若业务编号从 1 开始,公式通常是 (number - 1) / pageSize。不要只贴一个 % 就称为通用分页。
自增和自减是带副作用的表达式
int count = 5;
int before = count++; // before=5, count=6
int after = ++count; // count=7, after=7- 后置
count++的表达式值是修改前的值,然后变量加一; - 前置
++count先修改变量,表达式值是修改后的值。
循环更新中 count++ 很常见。不要在同一复杂表达式里多次读写同一变量:
int result = count++ + ++count; // 规则确定,但维护成本高拆开能保留意图:
int first = count;
count++;
count++;
int second = count;
int result = first + second;溢出与 exact 方法
int area = width * height;即使 width 和 height 各自有效,乘积也可能溢出。需要失败而不是回绕时:
int area = Math.multiplyExact(width, height);若先转 long:
long area = (long) width * height;cast 必须在乘法之前;long area = width * height 会先以 int 计算并可能已经溢出。
专业速查
| 场景 | 规则 |
|---|---|
| 整数除法 | 商向零截断 |
| 浮点除零 | 无穷或 NaN,不抛整数除零异常 |
| 余数符号 | 跟被除数 |
| 非负循环索引 | Math.floorMod,要求模数为正 |
| 负数奇偶 | value % 2 != 0 |
乘法升为 long | 运算前转换一个操作数 |
| 要检测溢出 | Math.*Exact 或显式边界检查 |
++/-- | 简单更新可用,避免与其他副作用混合 |
离开这一页前
用 -10 / 3、-7 % 3 和 Math.floorMod(-1, 3) 检验自己能否准确写出负数规则;再解释为什么 long result = intValue * otherInt 仍可能先溢出。
算术得到数值,程序还要把条件组合起来。