应优先使用 String 构造 BigDecimal,因为 double 构造会固化浮点误差,而字符串能无损还原十进制数值和精度;valueOf() 虽更安全但仍受限于原始 double 精度。

因为 double 类型本身无法精确表示大多数十进制小数,用它构造 BigDecimal 会把已丢失的精度“固化”进去,而字符串是原始、无损的十进制文本表达,能确保 BigDecimal 内部数值与业务意图完全一致。
double 构造函数会继承浮点误差
Java 中的 double 遵循 IEEE 754 标准,用二进制存储十进制数。像 0.1、0.3、2.3 这类常见小数,在二进制中是无限循环小数,必须截断,导致实际存储值本就不等于你写的字面量。
例如:new BigDecimal(0.1) 并不等于 0.1,而是 0.1000000000000000055511151231257827021181583404541015625 —— 这个结果不是 BigDecimal 的 bug,而是它忠实地包装了那个“已经不准”的 double 值。
String 构造函数直接解析十进制文本
字符串如 "0.1"、"2.30" 是纯 ASCII 字符序列,BigDecimal 会按十进制规则逐位解析,跳过二进制转换环节,因此能 100% 还原你输入的数值和精度。
立即学习“Java免费学习笔记(深入)”;
- new BigDecimal("0.1") → 精确等于 0.1
- new BigDecimal("2.30") → 标度(scale)为 2,保留两位小数含义
- 即使写 "0.1000",也会被识别为标度 4 的值,语义清晰可追溯
替代方案:valueOf() 比 double 构造更安全,但仍有局限
BigDecimal.valueOf(double) 内部做了优化,尝试用更合理的算法还原 double 的“最接近十进制解释”,对很多常见值(如 0.1、0.01)效果不错,但它仍依赖于原始 double 的精度上限。
- 它适合从已有 double 变量(如方法返回值、配置读取)转 BigDecimal
- 但若原始 double 来自计算(比如
0.1 + 0.2),结果已是 0.30000000000000004,valueOf 也只能基于这个错误值做修复 - 而字符串来自源头输入(如数据库字段、用户表单、配置文件),天然规避了中间 double 环节
不只影响初始化,还牵连后续运算和比较
一旦用错构造方式,误差会延续到所有操作中:
- 加减乘除结果偏差累积
- divide() 容易因微小余数触发
ArithmeticException: Non-terminating decimal expansion - equals() 比较失败(因标度不同或值本身偏移),必须改用
compareTo()


















