Java运算未超出long取值范围却出现Long类型溢出问题排查
问题产生原因
核心原因是Java算术运算的类型提升规则+运算优先级导致的int类型提前溢出:
- 运算优先级上括号优先级最高,代码中会先计算括号内的
byteValue + shortValue + intValue部分,这部分运算完全在int类型层面完成:- Java规定,byte、short类型参与算术运算时,会先自动提升为int类型再计算
- 三个值相加的理论结果是
127 + 32767 + 2147483647 = 2147516541,已经超过int类型的最大值2^31-1 = 2147483647,这一步就已经发生了有符号整数溢出 - 溢出后得到的int结果是
-2147450755,这个错误值后续和long类型的10L、50000L运算时才会被提升为long,错误已经无法逆转,最终计算得到-2147450755 *10 +50000 = -21474457550,和实际运行的输出完全吻合。
- 代码中虽然在乘法和加法步骤写了10L、50000L的long类型字面量,但这两个long值参与运算的时机晚于括号内的int加法,无法避免括号内的溢出。
修正方案
只需要在括号内的加法运算阶段,就把参与计算的值提前转为long类型,让整个加法过程以long类型完成,从根源避免int溢出即可,修正后的代码如下:
public class Main { public static void main(String[] args) { byte byteValue = 127; short shortValue = 32767; int intValue = 2147483647; // 把括号内第一个值强转为long,后续所有加法运算会自动提升为long类型计算 long longTotal = 50000L + 10L * ((long)byteValue + shortValue + intValue); System.out.println(longTotal); } }
运行修正后的代码,输出结果为21475215410,和预期的2.14*10^10量级结果一致。
注意:只要涉及int及以下类型的算术运算,不要默认"最后赋值给long就不会溢出",必须确认每一步中间运算的结果都没有超出当前运算类型的取值范围,否则就会出现这类隐蔽的溢出错误。
内容的提问来源于stack exchange,提问作者Marco.py
相关产品推荐
相关产品推荐

