在系统开发过程中,涉及到金额的处理时,选择合适的数据类型非常重要,要求确保精度,不能有误差。
春虫杂记
10年+一线程序员的自留地,记录技术、职场、生活中的点滴。
今天看到一则帖子,公司内总监和组长,因为金额的数据类型,到底应该用 BigDecimal 还是 Long 而吵了起来。
在一线实践过程中,有的场景选择 Long,有的选择 BigDecimal,都有各自的道理。
国内最小结算单位为分,很多业务系统使用 long 为数据类型,在数据库中按分来存储金额。阿里巴巴开发规约中提到,“【强制】任何货币金额,均以最小货币单位且整型类型来进行存储。”
如果系统中的金额运算都是简单的整数运算(加法、减法、乘以整数倍数、除以整数倍数),使用 Long类型表示金额是可取的,尤其是那些对性能要求较高的系统,由于 long 为基本类型, 使用long类型处理整数运算通常比使用 BigDecimal更快。
BigDecimal可以表示任意精度的小数,提供了丰富的舍入模式,可以根据业务需求选择合适的舍入规则,遵循金融行业标准。同时,BigDecimal提供了一组
内置的方法来执行精确的算术运算,包括加法、减法、乘法和除法,而不会出
现浮点数运算的误差。
BigDecimal提供了强大的功能,但是使用不当会产生故障,下面看一个线上问题。
# 问题现象
计算商品金额报错,导致订单无法支付。
#?问题原因
BigDecimal 在金额计算中丢失精度,看下面一段代码:
?public static void main(String[] args) {
BigDecimal bigDecimal=new BigDecimal(88);
System.out.println(bigDecimal);
bigDecimal=new BigDecimal("8.8");
System.out.println(bigDecimal);
bigDecimal=new BigDecimal(8.8);
System.out.println(bigDecimal);
bigDecimal=new BigDecimal(8.8f);
System.out.println(bigDecimal);
}
以上代码执行结果如下:
88
8.8
8.800000000000000710542735760100185871124267578125
8.80000019073486328125
可以看到,当BigDecimal 构造器使用 double 或者 float 这些浮点数据类型时,会丢失精度,导致计算商品金额不正确。
涉及金额的数据类型,多数场景下,使用 BigDecimal 还是 long ,只要使用得当,都可以解决问题。文章开头,总监坚持使用 long,说曾经使用 BigDecimal 有过问题,很可能就如文中所述,是由于不合理的使用产生的。
了解了两者间的差异后,在具体实践中,按照团队中的规范和约定来执行即可。如果总监建议使用 long,那使用 long 就好喽~