Java整数溢出和浮点数精度丢失是底层机制决定的必然现象,需在设计阶段选对类型、方法与边界:整数优先用long或BigInteger,浮点数精确场景必用BigDecimal,字符串转数字须校验,舍入操作应使用Math.round或BigDecimal.setScale。

Java 中整数溢出和浮点数精度丢失不是“偶尔发生的问题”,而是由底层数据表示机制决定的必然现象。处理它们的关键,不是等出错了再补救,而是在设计阶段就选对类型、用对方法、设好边界。
整数溢出:别让计算在静默中翻车
int 类型加到最大值再加 1,结果变成负数——这不是 bug,是 Java 的默认行为。它不会报错,但逻辑已错。
- 优先声明为 long:对金额、计数器、时间戳毫秒等可能累积的场景,直接用 long 声明,避免后期转换时才暴露问题
- 运算阶段就升维:比如
int money = 1_000_000_000; int years = 30;,别写long total = money * years;(乘法已在 int 内溢出),改写成(long) money * years - 需要转小类型时,用安全方法:
Math.toIntExact(longValue)溢出直接抛ArithmeticException;不想抛异常可用 Guava 的Ints.saturatedCast()(溢出时返回Integer.MAX_VALUE或MIN_VALUE) - 超 long 范围?用 BigInteger:它以字符串方式存储,无固定上限,适合超大 ID、密码学运算等
浮点数精度丢失:十进制小数本就不该用 float/double 存
0.1 + 0.2 ≠ 0.3,是因为 0.1 在二进制里是无限循环小数,只能近似存储。这不是 Java 的缺陷,是所有基于 IEEE 754 的语言共性。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 金额、配置值等必须精确的场景,从字符串构造:
new BigDecimal("12.8")或BigDecimal.valueOf("12.8"),绝不用new BigDecimal(12.8)(后者传入的是 double 近似值) - 金融计算全程用 BigDecimal,单位建议用“分”:避免小数,减少 scale 操作,也规避除法时的舍入争议
- float → double 不是“变精确”,只是把那个不精确的值用更多位存下来;
double d = 12.8F;后,d == 12.8是 false - 浮点数比较别用 ==:改用
Math.abs(a - b) < epsilon,或统一转成 BigDecimal 后用compareTo()
字符串转数字:别跳过校验这一步
用户输入或配置文件里的数字字符串,可能超范围、含空格、带符号,直接 parse 很容易崩。
立即学习“Java免费学习笔记(深入)”;
- 用
Long.parseLong(s)得到 long 后,再用Math.toIntExact()转 int,比手动判断l > Integer.MAX_VALUE更简洁安全 - 字符串可能超 long?直接上
new BigInteger(s)或new BigDecimal(s),它们能处理任意长度数字字符串 - float/double 字符串解析不适用
Math.toXXXExact(),因为浮点本身没有“精确溢出”概念,Infinity 和 NaN 是合法值
小数转整数:截断 ≠ 四舍五入
(int) 3.9 得 3,(int) -3.9 得 -3——这只是丢掉小数部分,不是四舍五入,业务上常导致偏差。
- 需要四舍五入时,用
Math.round(double)(返回 long)或Math.round(float)(返回 int) - 注意:
Math.round(-2.5)在 Java 7+ 是 -2(银行家舍入),而(long) -2.5是 -2,表面一样但逻辑不同,不能混用 - 如果要控制舍入模式(如向上、向下、半偶),BigDecimal 的
setScale(scale, RoundingMode)更可靠

















