Java中0.1+0.2≠0.3是因float/double的IEEE 754二进制存储无法精确表示十进制小数,解决需换数据类型(BigDecimal或整数)、换构造方式(字符串初始化)、换比较逻辑(容差或compareTo)。

Java 中用 +、-、*、/ 等算术运算符直接计算小数时,0.1 + 0.2 ≠ 0.3 这类问题不是运算符的错,而是 float/double 类型底层存储机制决定的——它们无法精确表示大多数十进制小数。解决的关键不在“怎么改运算符”,而在于**换数据类型、换构造方式、换比较逻辑**。
别用 float/double 做精确算术运算
算术运算符本身没有精度控制能力,它只是按 IEEE 754 规则对二进制浮点数做运算。只要操作数是 float 或 double,结果就天然带误差。比如:
-
0.1 + 0.2→ 得到0.30000000000000004 -
1.0 - 0.9→ 得到0.09999999999999998 -
4.015 * 100→ 得到401.49999999999994
这些都不是 bug,是二进制表示十进制小数时的必然现象(类似十进制写不出精确的 1/3)。所以第一步就是:涉及金额、计费、库存、配置阈值等需要“一分不差”的场景,彻底放弃 float/double 作为运算主体。
用 BigDecimal 替代,但必须正确初始化
BigDecimal 是 Java 提供的高精度十进制计算工具,但它不是“用了就准”,关键在初始化方式:
- ✅ 正确:用字符串构造 —
new BigDecimal("0.1")或BigDecimal.valueOf(0.1)(后者内部转字符串) - ❌ 错误:用 double 字面量构造 —
new BigDecimal(0.1),此时传入的 0.1 已经是失真后的二进制近似值
之后所有运算都调用方法,不用算术运算符:
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
- 加:
a.add(b) - 减:
a.subtract(b) - 乘:
a.multiply(b) - 除:
a.divide(b, scale, RoundingMode.HALF_UP)(必须指定小数位数和舍入模式)
浮点数比较不能用 ==,要设容差或用 compareTo
如果因历史原因仍需保留 double 参与逻辑判断(如性能敏感中间值),比较时绝不能写 if (a == b):
- 推荐容差法:
Math.abs(a - b) (根据业务精度选阈值) - 更稳妥用 BigDecimal:
new BigDecimal(Double.toString(a)).compareTo(new BigDecimal(Double.toString(b))) == 0 - 注意:
BigDecimal.equals()比较的是值+精度,compareTo()只比数值大小,业务中应优先用后者
整数运算是最简单可靠的替代方案
对货币、百分比、权重等有固定小数位的场景,可降级为整数处理:
- 金额统一存“分”:199.99 元 → 存 19999(int/long),运算全程整数加减
- 百分比统一乘 100:3.5% → 存 350(代表 0.35%),显示时再除以 100.0
- 优势:零误差、无对象开销、线程安全、数据库映射自然
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










