java基本数据类型无法避免精度丢失,因float/double按ieee 754以二进制存储十进制小数导致截断误差;精确计算应禁用float/double,改用正确初始化的bigdecimal,并在数据库、传输、运算各环节严格隔离double污染。

Java 基本数据类型本身无法避免精度丢失——这是它们的固有特性,不是使用方式的问题。float 和 double 按 IEEE 754 标准用二进制存储十进制小数,像 0.1、0.2、0.3 这类常见数值在二进制中是无限循环小数,必须截断,误差从赋值那一刻就已产生。所以,“用对基本类型”不能解决精度问题;真正可行的是绕开它们。
别用 float/double 做精确计算
只要业务要求结果严格等于数学预期(比如金额、计费、计量、配置比例),就禁止把 float 或 double 当作运算主体。这不是过度设计,而是类型语义错配:
- float:32 位,有效数字约 6–7 位,连 1234567.1 都可能存不准
- double:64 位,有效数字约 15–16 位,看似够用,但 0.1 + 0.2 仍输出 0.30000000000000004
- 整数类型(byte/short/int/long)虽无小数精度问题,但加减乘易溢出;long 最大值约 9.2×10¹⁸,超限即翻转,不报错
用 BigDecimal 替代,但必须正确初始化
BigDecimal 不是“修复”浮点数,而是换了一套系统:用字符串建模十进制数,内部用整数运算模拟四则运算。关键不在“用了”,而在“怎么用”:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- ✅ 正确构造:new BigDecimal("19.99") 或 BigDecimal.valueOf(19.99)(后者内部调用 Double.toString(),安全)
- ❌ 绝对禁止:new BigDecimal(19.99) —— 此时 19.99 已是 double 近似值,错误被原样固化
- 前端传参、配置文件读取、用户输入等原始来源,应保持字符串形态,直通 BigDecimal 构造
数据库与序列化环节同步隔离 double
精度污染常发生在上下游交接处:
- 数据库字段必须定义为 DECIMAL(18,2) 等定点类型,而非 FLOAT/DOUBLE
- JDBC 查询时用 resultSet.getBigDecimal("amount"),绝不调用 getDouble() 再转
- 写入时用 preparedStatement.setBigDecimal(1, amount),跳过 double 中间层
- JSON 序列化(如 FastJSON)需启用 WriteBigDecimalAsPlain,否则 toPlainString() 不生效,"1.00" 可能变成 "1"
运算过程显式控制标度和舍入
加减法天然保精度(标度自动对齐),但乘除必须人工干预:
- multiply():建议用双参数重载,如 a.multiply(b, MathContext.DECIMAL128)
- divide():必须指定标度和舍入模式,例如 a.divide(b, 2, RoundingMode.HALF_EVEN)(银行家舍入,金融常用)
- 避免无参 divide():除不尽时直接抛 ArithmeticException
- 比较大小不用 ==,用 compareTo() 返回 -1/0/1
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










