Java里数字存货币金额,double和BigDecimal怎么选
在公司做支付系统这几年,最让我头疼的不是什么高并发架构,而是Java里数字类型到底怎么存货币金额。数字类型选错,报表上真金白银就对不上,领导看着数字皱眉头,背锅的永远是开发。
很多新人写金额字段,手指一滑就用了double,觉得64位精度够了。但double底层是IEEE 754二进制浮点,十进制的0.1在二进制里是无限循环小数,根本存不精确。0.1加0.2的结果是0.30000000000000004,金额越小、交易笔数越多,误差像滚雪球一样积出来。

正经做法是用BigDecimal。但坑在构造方式上——千万别写new BigDecimal(0.1),那等于把double的误差又喂进去。必须用字符串:new BigDecimal("0.1")。运算时配合setScale(2, RoundingMode.HALF_UP)锁死两位小数,结果才不会出现第三个小数位。
另一种更省心的思路:全程用long存"分"。19.99元就存1999,数据库字段bigintjava+数字+货币,彻底绕开浮点运算。展示层用除以100转回元,前后端接口约定好"单位是分",比BigDecimal还少一层心智负担,特别适合电商那种高频小额场景。
我踩过最惨的一次,线上月度对账差了三块钱Java里数字存货币金额,double和BigDecimal怎么选,排查两天定位到某处退款逻辑用了double做四舍五入,百万笔订单攒出来的误差。后来把全链路金额统一成BigDecimal,代码review时专门盯数字类型,再没出过岔子。
