java类型转换精度丢失是设计使然,关键在于明确语义:浮点转整数禁用(int)截断,应依业务选math.round或tointexact;long转int须范围校验,否则溢出绕回致线上故障。

Java 中类型转换引发的精度丢失,不是偶然 bug,而是类型系统按设计执行的结果。关键不在“能不能转”,而在“你有没有明确告诉程序你要什么语义”。下面这些做法,是经过大量金融、电商、计费系统验证过的实战要点。
浮点数转整数:别用 (int) 截断,要写清楚取整意图
直接写 (int)3.9 得到 3,(int)-3.9 得到 -3 —— 这是向零截断,不是业务常说的“四舍五入”。多数业务场景需要的是离最近整数更近的值。
- 需要四舍五入:用
Math.round(d)(返回 long)或Math.round(f)(返回 int) - 转 int 且怕溢出:用
Math.toIntExact(Math.round(d)),超范围直接抛ArithmeticException,不静默出错 - 真只需要丢小数:确认业务逻辑是否允许“砍掉”而非“向下取整”,比如时长统计中“不足1秒不算”才适用
高精度整型降级前,必须做范围校验
long 转 int 看似简单,但第 2147483648 个订单 ID 强转后会变成 -2147483648。Java 不报错,只绕回,问题在线上才暴露。
- 手动检查:
if (value >= Integer.MIN_VALUE && value 再转 - 优先用 JDK 安全方法:
Math.toIntExact(longValue),自动校验并抛异常 - 若允许饱和(溢出取边界值):用 Guava 的
Ints.saturatedCast(longValue)
金额与配置值:全程用字符串初始化 BigDecimal
float/double 本身无法精确表示 0.1、0.01 等十进制小数,用它们构造 BigDecimal 只是把误差“固化”下来。
- 正确方式:
new BigDecimal("19.99")或BigDecimal.valueOf(1999).divide(BigDecimal.TEN, 2, RoundingMode.HALF_UP) - 绝对避免:
new BigDecimal(0.1)—— 它实际存的是 0.1000000000000000055511151231257827021181583404541015625 - 数据库读取金额后,别先转 double 再塞进 BigDecimal;应从 ResultSet 的
getString()拿原始字符串,再构建
运算阶段就防溢出,别等赋值才补救
int 相乘溢出发生在运算过程,不是赋值那一刻。写 int a = 1_000_000_000; int b = 30; long c = a * b;,乘法已在 int 范围内翻车,再接 long 也救不回来。
- 提前升维:
long c = (long) a * b或long c = a * (long) b - 累计类变量(如总金额、时间戳毫秒)直接声明为
long,不依赖后期转换 - 对可能超限的中间结果,用
BigInteger替代,尤其在幂运算、ID 合成等场景
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











