强制类型转换是强行截断而非适配,易致静默错误;浮点转整数用(int)会向零截断,需四舍五入时用Math.round();long转int可能符号翻转引发故障;大数运算应提前升维为long或BigInteger。

强制类型转换(显式转换)不是“让数据更合适”,而是“强行塞进更小的盒子”——盒子装不下,就砍掉、绕回、失真。隐患不在语法报错,而在结果静默错误,尤其在金额、ID、计时、统计等关键业务中,可能造成资损或逻辑崩坏。
浮点数转整数:(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单位不算”,比如视频播放时长按秒计费,“0.9 秒不计费”才适用
大整数降级:long → int 不是赋值问题,是语义失控
Java 不拦你写 (int)2147483648L,但它会默默变成 -2147483648——高位字节被丢弃,符号位翻转,ID、订单号、时间戳毫秒一旦这样转,线上故障几乎必然发生。
- 手动校验:转前加判断
if (value >= Integer.MIN_VALUE && value - 用安全 API:
Math.toIntExact(longValue)自动检查并异常中断 - 若需饱和处理(溢出取边界):引入 Guava 的
Ints.saturatedCast(longValue)
金额类数据:用 double 构造 BigDecimal 就是固化误差
new BigDecimal(0.1) 看似写的是 0.1,实际存的是 0.1000000000000000055511151231257827021181583404541015625——double 本身无法精确表示十进制小数,强转只是把误差锁死。
- 正确初始化:用字符串
new BigDecimal("19.99")或BigDecimal.valueOf(1999).divide(...) - 数据库读取:别从
getDouble()拿再转,改用getString()获取原始文本再构建 - 配置/参数传入:统一走字符串解析,避免中间经由 float/double “污染”
运算过程中的隐性溢出:错在计算,不在赋值
写 int a = 1_000_000_000; int b = 30; long c = a * b;,乘法已在 int 范围内溢出(10^9 × 30 = 3×10^{10} > 2^{31}-1),结果错误再赋给 long 也救不回来。
- 提前升维:写成
long c = (long) a * b或long c = a * (long) b - 累计型变量(总金额、毫秒时间戳、计数器)直接声明为
long,不依赖后期转换 - 幂运算、ID 合成等高风险场景,直接用
BigInteger
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











