Skip to content

面试速答(先看这里)

**一句话结论:**所以,BigDecimal的适用场景是需要高精度计算的金融应用,如货币计算、利率计算等。

60秒标准回答:

大家都知道,不能用Float和Double来表示金额,会存在丢失精度的问题

那么要表示金额,业内有两种做法

1、单位为分,数据库存bigint,代码中用long。如100.16元,存储为10016(在不考虑多币种的情况下)

**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点

回答主线:

  • **要点1:**2、单位为元,数据库用decimal,代码中用BigDecimal( 我们一般数据库存储的是decimal(18,6) )。
  • **要点2:**这两种,其实我们都用过,而且现在也还都在用,因为他们都有各自的优缺点以及适用场景。
  • **要点3:**首先说 BigDecimal , BigDecimal 是 Java 中用于精确计算的类,特别适合于需要高精度数值计算的场景,如金融、计量和工程等领域。
  • **要点4:**所以,Long的适用场景是适合于不涉及小数计算的大整数运算,如某些计数应用或者金额以整数形式表示。
  • **要点5:**总结来说,对于绝大多数涉及货币计算的应用,推荐使用 BigDecimal ,因为它提供了必要的精度和灵活性,尽管牺牲了一些性能。

**记忆锚点:**BigDecimal → long → decimal → Long → Java → bigdecimal

关键取舍:

  • 其特点如下: 性能高 :作为基本数据类型, long 在处理速度上比 BigDecimal 快很多。
  • 容量限制 : long 可以表示的最大值为 (2^{63}-1),最小值为 (-2^{63})。
  • 不适合精确的小数运算 : long 无法处理小数,如果需要代表金额中的小数部分(如厘),则需要自行管理这一部分。

易错提醒:

  • 大家都知道,不能用Float和Double来表示金额,会存在丢失精度的问题。

加分表达:

  • 如100.16元,直接存成100.16 这两种,其实我们都用过,而且现在也还都在用,因为他们都有各自的优缺点以及适用场景。
  • 首先说 BigDecimal , BigDecimal 是 Java 中用于精确计算的类,特别适合于需要高精度数值计算的场景,如金融、计量和工程等领域。
  • 所以,BigDecimal的适用场景是需要高精度计算的金融应用,如货币计算、利率计算等。

追问准备:

  • 围绕「BigDecimal」:底层原理是什么?使用时有哪些边界和常见坑?
  • 围绕「long」:底层原理是什么?使用时有哪些边界和常见坑?
  • 围绕「decimal」:底层原理是什么?使用时有哪些边界和常见坑?
  • 如果线上出现异常,你会如何定位、验证并规避?

典型回答 ​

大家都知道,不能用Float和Double来表示金额,会存在丢失精度的问题。

📄 ✅为什么不能用浮点数表示金额?

打开文档:✅为什么不能用浮点数表示金额?

那么要表示金额,业内有两种做法:

1、单位为分,数据库存bigint,代码中用long。如100.16元,存储为10016(在不考虑多币种的情况下)。

2、单位为元,数据库用decimal,代码中用BigDecimal(我们一般数据库存储的是decimal(18,6))。如100.16元,直接存成100.16

这两种,其实我们都用过,而且现在也还都在用,因为他们都有各自的优缺点以及适用场景。

首先说BigDecimal,BigDecimal 是 Java 中用于精确计算的类,特别适合于需要高精度数值计算的场景,如金融、计量和工程等领域。其特点如下:

  • 精确度高:BigDecimal 可以表示非常大或非常精确的小数,而不会出现浮点数那样的舍入误差。
  • 灵活的数学运算:它提供各种方法进行精确的算术操作,包括加减乘除和四舍五入等。
  • 控制舍入行为:在进行数学运算时,你可以指定舍入模式,这对于金融计算非常重要。

所以,BigDecimal的适用场景是需要高精度计算的金融应用,如货币计算、利率计算等。比如我们的结算系统、支付系统、账单系统等,都是用BigDecimal的。

其次,再说Long,long 是 Java 的一种基本数据类型,用于表示没有小数部分的整数。其特点如下:

  • 性能高:作为基本数据类型,long 在处理速度上比 BigDecimal 快很多。
  • 容量限制:long 可以表示的最大值为 (2^{63}-1),最小值为 (-2^{63})。这在大多数应用程序中已经足够,但在表示非常大的数或需要小数的计算中则不适用。
  • 不适合精确的小数运算:long 无法处理小数,如果需要代表金额中的小数部分(如厘),则需要自行管理这一部分。

所以,Long的适用场景是适合于不涉及小数计算的大整数运算,如某些计数应用或者金额以整数形式表示。比如我们的额度系统、积分系统等。

很多人会有疑惑,什么情况下会出现需要比分还小的单位呢?其实就是在很多需要运算的场景,比如说金融的费率、利率、服务费的费率等等,这些都是很小的,一般都是万分之几或者千分之几。而一旦有一个单位为元的金额和一个"率"相乘的时候,就会出现小于分的单位。

那有人说,遇到分我就直接四舍五入不就行了么,反正结算也是按照分结算的。这样做会有问题,我举个例子。

我一笔账单,有两笔订单,金额都是1元,存储的时候按照分存储,即100分,然后我的服务费费率是0.004。

如果是以分为单位,long存储和表示的话,那么两笔订单分开算费率的话:100*0.004 = 0.4 ,四舍五入 0, 两笔加在一起,收入的费率就是0分。

但是如说是以元为单位,bigdecimal存储和表示的话,那么两笔订单分开算费率的话:1*0.004 = 0.004 , 两笔加在一起0.008,当我要结算的时候,再做四舍五入就是0.01元,即1分钱。

所以,因为long在计算和存储的过程中都会丢失掉小数部分,那就会导致每一次都被迫需要四舍五入。而decimal完全可以保留过程中的数据,再最终需要的时候做一次整体的四舍五入,这样结果就会更加精确!

所以,如果你的应用需要处理小数点后的精确计算(如金融计算中常见的多位小数),则应选择 BigDecimal。

如果你的应用对性能要求极高,并且没有乘除类运算,不需要很小的精度时,那么使用 long 可能更合适。

总结来说,对于绝大多数涉及货币计算的应用,推荐使用 BigDecimal,因为它提供了必要的精度和灵活性,尽管牺牲了一些性能。如果确定不需要处理小数,并且对执行速度有极端要求,使用 long 可能更适合。