首页 > 其他分享 >争论不休的一个话题:金额到底是用Long还是BigDecimal?

争论不休的一个话题:金额到底是用Long还是BigDecimal?

时间:2024-04-18 09:57:29浏览次数:17  
标签:存储 BigDecimal 金额 Long 计算 精度 争论不休

在网上一直流传着一个争论不休的话题:金额到底是用Long还是用BigDecimal?这个话题一出在哪都会引起异常无比激烈的讨论。。。。
比如说这个观点:算钱用BigDecimal是常识

image.png
image.png

有支持用Long的,将金额的单位设计为分,然后乘以100,使用Long进行存储以及计算,这样不用担心小数点问题。
image.png
并且一些银行系统就会选择用Long
image.png
还有,最最最牛逼的万能大法:用String

image.png
成年人不做选择题,Long跟BigDecimal都用。。。
image.png
还有一种就是封装一个金额的基类,对金额进行统一处理。
image.png

排除float和double

当然,对于金额,首先我们要排除的就是float和double。它们不适合用于精确的金融计算,因为floatdouble是基于IEEE 754标准的浮点数表示,它们无法精确地表示所有的十进制小数。这会导致在进行财务计算时出现舍入误差,这些误差可能会累积并导致不可预测的结果。

关于带精度的计算,我们不推荐使用float以及double,推荐使用BigDecimal,具体原因请参考:聊一聊_BigDecimal_使用时的陷阱

选择Long

Long类型在Java中用于存储64位整数。它的主要优点是速度快,因为整数运算在CPU层面是非常高效的。另外,Long类型也占用较少的内存,并且整数类型(BIGINT)在数据库中占用较少的存储空间。

但是Long类型在处理金额时有几个明显的缺点:

  1. 精度问题Long只能存储整数,无法直接表示小数。使用Long来表示以分为单位的金额(例如,100表示1元),此时就会失去小数的精度。即使使用某种方式来表示小数(例如,乘以100或10000),也会遇到舍入误差的问题。并且这种计算方式也会增加计算的复杂度。
  2. 浮点数问题:虽然这不是直接使用Long的问题,但如果你尝试将Long与浮点数(如doublefloat)进行转换以进行计算(比如汇率计算等),还是会遇到浮点数精度问题,这可能导致在财务计算中出现不可接受的误差。

在阿里巴巴的开发手册中建议使用Long。
image.png
但是在一些金融系统当中,对小数位要求比较高的,比如精确到小数点后6位,那么我们使用Long进行存储,每次在计算时都要除以或者乘以1000000,那么计算的开销就很大了。

并且,如果在需求确认时,我们无法知道金额要求的小数位,那我们使用Long也是不行的,我们并不知道需要乘以或者除以多少个0。

选择BigDecimal

BigDecimal是Java提供的一个类,用于任意精度的算术运算。它的主要优点是提供了高精度的计算,这对于金融和货币计算来说是非常重要的。BigDecimal可以表示任意大小的正数、负数或零,并可以精确控制舍入行为。并且在数据库中存储时也有对应的类型进行匹配,比如MySQL的DECIMAL类型提供了精确的数值存储,可以匹配BigDecimal的精度。

但是BigDecimal也有一些缺点:

  1. 性能:与Long相比,BigDecimal的性能较差。因为它的运算需要更多的内存和CPU时间。
  2. 复杂性:使用BigDecimal进行运算比使用Long或基本数据类型更复杂。你需要考虑舍入模式、精度等因素。
  3. 在数据库中需要更多的存储空间来存储小数部分。

而在Mysql的开发手册中,建议金额需要进行小数位计算时,存储要使用Decimal,否则我们要将金额乘以对应小数位的倍数变成BIGINT进行存储。
image.png

总结

基于上述对LongBigDecimal的优缺点分析,我们可以得出以下结论:

在金额计算层面,即代码实现中,推荐使用BigDecimal进行所有与金额相关的计算。BigDecimal提供了高精度的数值运算,能够确保金额计算的精确性,避免了因浮点数精度问题导致的财务误差。使用BigDecimal可以简化代码逻辑,减少因处理精度问题而引入的复杂性。

而在数据库存储方面,我们需要根据具体需求进行权衡。如果业务需求已经明确金额只需精确到分(如某些国家/地区的货币最小单位为分),并且我们确信不会涉及到需要更高精度的小数计算,那么可以使用Long类型进行存储,将金额转换为最小货币单位(如分)进行存储。这样可以节省存储空间并提高查询性能。

但是如果业务需求中金额的小数位数不确定,或者可能涉及多位小数的计算(如国际货币交易等),那么最好使用DECIMALNUMERIC类型进行存储。这些类型提供了精确的数值存储,可以确保数据库中的数据与应用程序中的BigDecimal对象保持一致,避免数据转换过程中可能引入的精度损失。

本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等

标签:存储,BigDecimal,金额,Long,计算,精度,争论不休
From: https://www.cnblogs.com/coderacademy/p/18142867

相关文章

  • PostgreSql: ERROR: value too long for type character varying(1) 定位字段方法
    报错原因设置的数据库字段长度为1,但实际的值超过规定字段,导致报错。解决方案首先,需要定位字段是哪个字段出现的报错,但可惜的是,并没有报出具体是哪个字段在报错,所以只能通过检查Schema,查看哪些字段是长度为1的,然后再进行值的比较,才能锁定位置。ERROR:valuetoolongfortype......
  • Command line is too long. Shorten command line for JooLunMallApiApplication or a
      在启动微服务项目的某个时候,一直启动不起来,报Commandlineistoolong.ShortencommandlineforApplicationoralsoforApplicatio,在网上查阅资料后,发现这个问题,是因为启动命令太长(就是main方法类)。  解决方法:  选择工具栏的Run并下拉选Run,之后会有个弹窗,选择......
  • [NeuralPS2023]How Re-sampling Helps for Long-Tail Learning
    这篇文章作者写得非常详细,读起来非常舒适。Contribution:在long-taileddata中,re-sampling不一定有效。re-sampling的失败可能是对于不相关的context过拟合导致的,作者设计了实验论证了这一假说。在single-stage的框架下,作者提出了上下文转换增强(contextualtransformationau......
  • [Java SE] 经典问题:超出Java Long型(8字节/64位)的二进制比特流数据如何进行大数的数
    0问题描述经典问题:超出JavaLong型(8字节/64位)的二进制比特流数据如何进行大数的数值计算?近期工作上遇到了这个问题:需要将一个无符号数、且位长>=8字节(等于8字节时,首位bit为1,其他bit不全为0)的二进制字符串转为Java****对象(原始整数),进行整型运算、或浮点数运算浮点运算......
  • 并发编程之AtomicInteger,AtomicLong,LongAdder
    系列文章目录文章目录系列文章目录前言前言前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。AtomicInteger类是系统底层保护的int类型,通过提供执行方法的控制进行......
  • E. Long Inversions
    原题链接题解巧妙模拟题这种题目要从性质下手1.把翻转的区间实质化,我们可以发现序列中值为1的地方覆盖了偶数个区间,0的地方覆盖率奇数个区间,换句话说,如果1的地方覆盖区间个数为奇数,那么我们要新建立一个以它为起点的区间怎么模拟呢?我们维护一个到当前点的距离小于等......
  • 蓝桥杯备考随手记: BigInteger 和 BigDecimal
    在Java中,BigInteger和BigDecimal是用来处理大整数和高精度浮点数的类,分别属于java.math包。下面分别介绍这两个类的特点、用途和常用方法:BigInteger:特点:BigInteger类表示任意精度的整数,可以处理比long型和int型更大范围的整数。BigInteger是不可变的(immutable)类,一......
  • Longan Pi 3H简约外壳分享
    LonganPi3H简约外壳分享因为购买了LonganPi3H,它用的是H618,我记得香橙派zero2w也是这个芯片,不过我很喜欢sipeed的这个风格,特别好看,而且该有的都有,不说废话了,直接上图片和文件链接:https://pan.baidu.com/s/1d1pQBoDtDptA0vc__GnHZg提取码:deb2......
  • 常用API(一):BigDecimal
     解决小数运算失真的问题 packagecom.itheima.Math;importjava.math.BigDecimal;publicclassbigdecimal{publicstaticvoidmain(String[]args){System.out.println((0.1+0.2));//把小数转换成字符串BigDecimala1=newBigD......
  • LeetCode in Python 300. Longest Increasing Subsequence (最长递增子序列)
    求最长递增子序列是深度优先搜索(DFS)的一种应用,有两种比较好的方法可以解决。第一种是动态规划法,时间复杂度为O(n*n),即设置边界条件和更新迭代公式求解最优解。第二种使用二分查找将时间复杂度降为O(nlogn)。本文给出两种方法的实现代码及说明。示例:图1最长递增子序列输入......