强制类型转换不处理溢出,仅截断高位;安全转换需手动范围检查或使用math.tointexact。

强制类型转换本身不处理溢出,只截断高位
Java 中 (int) someLong 是无条件截断操作:直接丢弃高 32 位,保留低 32 位作为补码解释。它不会检查范围、不抛异常、也不做任何保护。所谓“处理风险”,其实是把风险转嫁给调用方——你得自己确保值在 Integer.MIN_VALUE 到 Integer.MAX_VALUE 之间。
常见错误现象包括:
-
long value = 2147483648L;强转后变成-2147483648(即Integer.MIN_VALUE) - 数据库主键或雪花 ID 被误转成负数,导致查不到记录或写入冲突
- 时间戳毫秒值(如
System.currentTimeMillis())直接强转,2038 年后必然溢出
必须手动加范围检查才能算“安全转换”
如果你坚持用强制转换,就得配套做显式边界判断。这不是可选项,是必要步骤。
- 先判
null(如果源是Long对象) - 再用
value >= Integer.MIN_VALUE && value 检查 - 只在通过时执行
(int) value,否则明确报错或 fallback - 注意:不要写成
value > Integer.MIN_VALUE && value ,边界值是合法的
示例:
public static int safeLongToInt(long value) {
if (value Integer.MAX_VALUE) {
throw new IllegalArgumentException("Cannot cast " + value + " to int");
}
return (int) value;
}
Math.toIntExact 是更简洁的替代方案
Java 8+ 提供了 Math.toIntExact(long),它内部做了和上面一样的范围检查,但封装得更干净。
- 值在范围内 → 返回对应
int - 超出范围 → 抛
ArithmeticException,不是IllegalArgumentException - 语义清晰:名字就表明“精确转换”,失败即溢出
- 比手写检查少出错,也避免重复逻辑
用法:
try {
int x = Math.toIntExact(someLong);
} catch (ArithmeticException e) {
// 处理溢出,比如记录日志、降级为 null 或抛业务异常
}
别忽略 long 值来自外部输入的场景
从数据库、HTTP 参数、JSON 解析拿到的 long,尤其要注意原始数据是否可能超限。
- MySQL 的
BIGINT可存9223372036854775807,远超int范围 - 前端传的时间戳单位可能是毫秒,后端若按秒处理再强转,容易漏掉除法
- Protobuf 或 JSON 库默认把数字解析为
long,哪怕业务上只用得着int
这时候光靠 Math.toIntExact 不够,得结合上下文做单位换算或协议约定——比如明确要求时间戳传秒级,那就要先 / 1000 再转,而不是直接强转原始值。










