java数值运算需从类型语义、api选择和显式校验三方面防控溢出与精度问题:优先使用math.addexact()等带溢出检查方法;bigdecimal构造禁用double,推荐字符串或valueof();包装类转换用valueof()而非new;精确计算禁用float/double,统一用bigdecimal并封装校验逻辑。

Java 中处理数值运算与包装类转换时,溢出和浮点精度问题不能靠“试运行”或“凭经验”,必须从类型语义、API 选择和显式校验三方面入手。
用带溢出检查的 Math 方法替代原始运算
基本类型(如 int、long)算术运算不抛异常,溢出静默发生。应主动使用 Math.addExact()、Math.multiplyExact() 等方法,它们在溢出时抛 ArithmeticException,便于及时拦截。
-
int result = Math.addExact(a, b);—— 比a + b安全,失败即暴露 - 对
BigInteger或BigDecimal运算,本身无溢出风险,但需注意构造方式:避免用double构造BigDecimal(如new BigDecimal(0.1)会引入二进制浮点误差) - 推荐用字符串构造:
new BigDecimal("0.1")或BigDecimal.valueOf(0.1)(后者内部也转为字符串再解析)
包装类转换优先用 valueOf(),避免 new Integer() 等已废弃方式
Integer.valueOf(int) 等方法有缓存机制(-128 到 127),既高效又避免无谓对象创建;而 new Integer(int) 已废弃,且绕过缓存,易引发 == 判断陷阱。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 自动装箱(如
Integer i = 100;)底层调用valueOf(),安全可靠 - 从字符串解析时,用
Integer.parseInt(s)获取基本类型再装箱,比Integer.valueOf(s)更明确——后者在解析失败时抛NumberFormatException,但不会处理溢出语义(如 "2147483648" 对 int 溢出,仍报格式错) - 若需严格区分“非法格式”和“合法但溢出”,可用
Integer.parseUnsignedInt(s, 10)(JDK 8+)配合范围校验,或直接用BigInteger解析后比较
浮点包装类(Float/Double)不用于精确业务计算
Float 和 Double 是 IEEE 754 二进制浮点,天生无法精确表示大多数十进制小数(如 0.1)。业务中涉及金额、比例、计数等需确定精度的场景,一律禁用 float/double 及其包装类。
- 用
BigDecimal表示,并指定RoundingMode(如HALF_UP)和scale(如 2 位小数) - 所有输入来源(JSON、DB、HTTP 参数)中的数字字段,若语义为精确值,应在反序列化时强制转为
BigDecimal字符串再构造,而非先转double - 日志或调试中打印
BigDecimal时,用toPlainString()而非toString(),避免科学计数法干扰可读性
统一数值边界与精度策略,在领域模型层封装校验逻辑
不要把溢出和精度判断散落在 Service 或 Controller 层。应在业务实体(如 Money、Quantity)中封装不可变状态与构造约束。
- 例如定义
Money类,构造时只接受BigDecimal并设固定 scale(如 2),内部用setScale(scale, HALF_UP)标准化 - 提供加减乘除方法,全部基于
BigDecimal运算,并在除法时强制要求传入scale和roundingMode - 对外暴露的 getter 返回
BigDecimal的不可变副本(或toBigIntegerExact()等安全转换),避免外部篡改内部状态
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










