bigdecimal 保留两位小数_一律使用 BigDecimal,避免后患?

你知道的越多,不知道的就越多,业余的像一棵小草!

你来,我们一起精进!你不来,我和你的竞争对手一起精进!

编辑:业余草

zhuanlan.zhihu.com/p/94144867

推荐:https://www.xttblog.com/?p=5116

一律使用 BigDecimal,避免后患?

一、背景

总在项目中看到 Double 与 BigDecimal 被用错的情况,竟然有人告诉我:“一律使用 BigDecimal,避免后患”,我相信这位兄弟肯定是被精度问题搞蒙了,因此我想同步一下我的使用姿势,仅提供参考。

二、两种类型使用过程中都有可能出坑

  1. double 的计算时容易出现不精确的问题
a052f350d9d9a511243cb441c4d59e17.png

double 的小数部分容易出现使用二进制无法准确表示。

如十进制的0.1,0.2,0.3,0.4 都不能准确表示成二进制。

具体原因相信大家都懂,我就不多说了。如果有不懂的可以私信我或者评论留言!

  1. dobule 的 = 比较要注意
808788144f3efe66a6bd2c67d98bf90a.png

dobule 小数超过 15 位的相等比较就不一定对了。都是 true。

  1. BigDecimal 的除法除不尽会出现异常:ArithmeticException
775b017aa1bc02a48b1850f50ea6dbd3.png

所以,使用 BigDecimal 进行除法运算一定要有精度!

  1. new BigDecimal(double) 结果也许不是你想要的

一般情况下都不使用 new BigDecimal(double) 应该使用 BigDecimal.valueOf(double)。

BigDecimal d1 = BigDecimal.valueOf(12.3);
//结果是12.3 你预期的
BigDecimal d2 = new BigDecimal(12.3);
//结果是12.300000000000000710542735760100185871124267578125

我想 12.300000000000000710542735760100185871124267578125 肯定不是你想要的结果,因此 new BigDecimal(double) 可能会产生不是你预期的结果,原理可以自行看一下底层源代码,还是比较容易搞懂的。

另:BigDecimal.valueOf(xxx) 是静态工厂类,永远优先于构造函数(摘自《Effecitve java》,此书也是非常推荐的一本经典书)

  1. BigDecimal 是不可变对象

如原来 d1=1.11 ,又加了一个数 2.11,这种操作要注意结果要指向新对象。

5cf33249de96ca3434536961e93f81fc.png

任何针对BigDecimal对象的修改都会产生一个新对象;

BigDecimal newValue = BigDecimal.valueOf(1.2222).add(BigDecimal.valueOf(2.33333));

BigDecimal newValue = BigDecimal.valueOf(1.2222).setScale(2);

总之每次修改都要重新指向新对象,才能保证计算结果是对的。

  1. BigDecimal 比较大小操作不方便,毕竟是对象操作

比较大小和相等都使用 compareTo,如果需要返回大数或小数可使用 max,min。且注意不能使用 equals。

69d727ad1b885dcbb6e5c00ae81bbf68.png

三、效率比较

比如:1 累加到 1000000(以本人机器 MacBookPro 2018 i7 2.2G)double 比 BigDecimal 快大约 10 倍

double: 2ms

BigDecimal:16ms

四、优缺点总结

double 的优缺点:

  1. double在计算过程中容易出现丢失精度问题

  2. 使用方便,有包装类,可自动拆装箱,计算效率高

BigDecimal 的优缺点:

  1. 精度准确,但做除法时要注意除不尽的异常

  2. BigDecimal 是对象类型,也没有自动拆封箱机制,操作起来总是有些不顺手

五、使用场景推荐

涉及到精准计算如金额,一定要使用 BigDecimal 或转成 long 或 int 计算。

若不需要精准的,如一些统计值:(本身就没有精确值)。

用户平均价格,店铺评分,用户经纬度等本就没有精准值一说的推荐使用 double 或 float,写代码更方便,计算效率也高得多。

值得一提的说,如果 double 或 float 仅是用于传值,并不会有精度问题,但如果参与了计算就要小心了。要区分是不是需要精准值,如果需要精准值,需要转成 BigDecimal 计算以后再转成 double。

但依然约定在 DTO 定义金额时使用 BigDecimal 或整形值,是为了减少或避免 double 参与金额计算的机会,避免出 bug。

其他1:代码中看到碰到让我觉得有问题的地方

以下代码在不同的类中抓出来的觉得用得不太恰当的地方:

d439bdd4b4e3b4b6a6564eaffb74bdca.png

代码中真的不需要那么多地方使用 BigDecimal,相反用到 BigDecimal 的地方并不多,反而用 Double 的地方更多。以上代码我希望的方式是:

e6e1ead69d19213481a716741526450b.png

提醒:DTO 中尽量使用包装类,防止反系列化时 null 的造成的格式转换异常

分析

经纬度:一般业务代码中也不太会去计算,仅用于传给地图api等,经纬度一般用于计算距离,如果保留到 6 位小数时其实已经是 1 米级别的了,也满足绝大多数场景了,因此使用 Double 是确实是可行的;

店铺平均消费:本身就是一个归纳统计值,也一般用来比较大小做参考,因此也用不着 BigDecimal;

当前价格:这个不一样了,为了减少 double 参与金钱计算,统一使用 BigDecimal 代替带有小数的金额;

其他2:关于 Mysql 中如何选用这两种类型

  1. 首先与 java 不同的是 mysql 是用来持久化数据的,而 java 中使用的数据一般更多的是过一下内存;

  2. 数据库都要除了指定数据类型指外还需要指定精度,因此在 DB 中 Double 计算时精度的丢失比 Java 高得多;

因为 Java 默认精确到 15-16 位了;

  1. 更改数据类型的成本,Mysql 比 Java 代码要难得多;

考虑到以上与 java 中不同几点,做点个人使用总结:

  1. 与商业金融相关字段要使用 Decimal 来表示,如金额,费率等字段;

  2. 参与各类计算如加,减,乘,除,sum,avg 等等,也要使用 Decimal;

  3. 经纬度,可以使用 double 来表示,这个可参考 Java,只要保证精度范围即可;

  4. 如果确实不确定使用什么 double 或 Decimal 哪种类型合适,那最好使用 Decimal,毕竟稳定,安全高于一切;

注:阿里的编码规范中强调统一带小数的类型一律使用 Decimal 类型,也是有道理的,使用Decimal 可以大大减少计算踩坑的概率。

99ca0d79c9c6d6cfed23e5125b75ee83.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/410038.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tcp 四次挥手_tcp三次握手和四次挥手

SYN:一个很小的包,tcp的第一个包(同步序列编号)ACK:确认响应SYN、ACK:为1表示确认连接FIN表示关闭连接,PSH表示有 DATA数据传输,RST表示连接重置。Acknowledge number(ack):确认号,大…

ssh登录服务器提示错误no hostkey alg

ssh登录服务器提示错误no hostkey alg ssh root192.168.1.100 -vvv提示失败:no hostkey alg 登录到192.168.1.100服务器 rm -rf /etc/ssh/ssh*key systemctl restart sshd #我还是移走了,没有删除。因为之前安装了telnet服务,因此不用担心连…

ms查约束具体代码_ECCV 2020附代码论文合集(CNN,图像分割)

ECCV 2020 共接受 1361 篇论文,涵盖了包括目标检测,语义分割,图像分类,点云,图像重建,神经网络模型等热门主题。对计算机视觉感兴趣的小伙伴们也许你们已经阅读完论文并对论文的内容跃跃欲试了吧&#xff0…

路径规划算法_自动驾驶汽车路径规划算法浅析

自动驾驶汽车的路径规划算法最早源于机器人的路径规划研究,但是就工况而言却比机器人的路径规划复杂得多,自动驾驶车辆需要考虑车速、道路的附着情况、车辆最小转弯半径、外界天气环境等因素。本文将为大家介绍四种常用的路径规划算法,分别是…

【转载】interpolation(插值)和 extrapolation(外推)的区别

根据已有数据以及模型(函数)预测未知区域的函数值,预测的点在已有数据范围内就是interpolation(插值), 范围外就是extrapolation(外推)。 The Difference Between Extrapolation and…

vue computed使用_vue computed正确使用方式

最近面试中,遇到一个小伙子,谈到了vue中的 computed 和 watch 区别,最后得到了一个让我瞠目结舌的答案,只用 watch,从不用 computed 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中…

Apache实验-目录别名

一、作用介绍 在一些情况下,我们的资源文件都在非/var/www/html目录下,例如/var/www/html/sohu。这样的话我们在输入网址的时候就需要在网站根目录下再输入完整的目录。所以我们可以定义一个别名来替代这个路径。可以简写网站的网址。 二、实例操作 目前…

黑苹果适合什么用途?_黑苹果系统,Ozmosis和四叶草、变色龙相比有什么区别和优势?...

黑苹果单系统,Ozmosis和四叶草、变色龙相比有什么区别和优势?黑苹果系统用于影视后期处理ozmosis由于调试灵活性差,每次调试都要刷bios,主板厂商提供的bios也就8mb,要把,ozmosis引导程序放进去,…

Apache的虚拟主机

一、虚拟主机的分类 基于IP的虚拟主机:一台服务器,多个ip,搭建多个网站 基于端口的虚拟主机:一台服务器,一个ip,利用不同端口,搭建多个网站 基于域名的虚拟主机:一台服务器&#xff…

zabbix解决中文乱码

解决中文乱码 yum install -y wqy-microhei-fonts #解决方法 中文乱码 \cp /usr/share/fonts/wqy-microhei/wqy-microhei.ttc /usr/share/fonts/dejavu/DejaVuSans.ttf #或者是服务器没有安装中文转载于:https://www.cnblogs.com/zhaojingyu/p/11438733.html

springboot启动过程_spring5/springboot2源码学习 -- spring boot 应用的启动过程

推荐阅读:Spring全家桶笔记:SpringSpring BootSpring CloudSpring MVC疫情期间“闭关修炼”,吃透这本Java核心知识,跳槽面试不心慌2020“闭关”跳槽季,啃透分布式三大技术:限流、缓存、通讯基本环境开发工具…

不出来信号 quartus_男人一旦动了真情,会向你发出这6个“信号”不爱的人装不出来...

恋爱的时候,女人都想知道一个男人是否真的爱你,是否真的在乎你,女人常常在猜测男人的心思。而对一个聪明的女人来说,她们会用眼睛,用心观察身边的那个男人。有人说如果男人对女人动了真情,他会在女人面前表…

python turtle画烟花_用Python写一个绚丽的烟花!

Python人工智能 - 一节课快速认识人工智能必备语言:python - 创客学院直播室​www.makeru.com.cn 哈喽大家好,小编来教大家如何用Python写一个绚丽的烟花,下面我们开始吧~ Turtle库Turtle,也叫海龟渲染器,使用Turtle库画图也叫海龟…

zabbix详解

官网地址 https://www.zabbix.com/documentation/3.0/manual/config/items/itemtypes/zabbix_agent 使用率 转载于:https://www.cnblogs.com/zhaojingyu/p/11440579.html

怎么把整个网站的代码中的一个词去掉_【杭州南牛网络】网站优化的最新优化方法...

【杭州南牛网络】如果你是一名企业主,你有建立企业官方网站的经验,在2-3年的运营过程中,我相信你至少对网站做了一次修改,甚至对SEO战略进行了重大调整。 原因很简单:当我们刚开始建一家公司时,很多时间都是…

数字电影打包内容(Packaging)

在数字电影领域,打包(Packaging)是指将节目素材(含图像、声音和字幕)按照一定的规则进行封装和组织,以用于节目传输和存储。在数字电影发展初期,下发到影院的数字节目没有统一的播放格式&#x…

阿里云盾AliYunDun服务IO超高

停止阿里云盾AliYunDun服务解决大量写磁盘问题-小内存ECS服务器 阿里云数据库在没备案,涉及大量IO操作时会自动启动阿里云盾这个服务,会导致服务器变得很卡,一直持续百分之99,一顿重启没有什么卵用! 最后关…

CORS 请求未能成功_当遇到跨域开发时, 我们如何处理好前后端配置和请求库封装(koa/axios版)...

我们知道很多大型项目都或多或少的采用跨域的模式开发, 以达到服务和资源的解耦和高效利用. 在大前端盛行的今天更为如此, 前端工程师可以通过nodejs或者Nginx轻松搭建起web服务器.这个时候我们只需要请求后端服务器的接口即可实现系统的业务功能开发.这个过程中会涉及到web页面…

java 数组存入数据库_Java中关于二维数组的理解与使用

今天练习的时候遇到一个题目,题目需求是这样的:需求说明:根据3个班各5名学生某门课程的成绩,正确使用二维数组计算如图所示3个班各自的总成绩分析:要实现这个功能需要存储两个信息:一个是班级信息&#xff…

sql删除元组_Lecture #02: 中级SQL

本专栏是对CMU15445的笔记的翻译,原文地址:https://15445.courses.cs.cmu.edu/fall2020/notes/02-advancedsql.pdf1 关系语言在20世纪70年代,Edgar Codd发布了一篇关于关系模型的论文。最初,他只定义了数据库在关系模型上运行查询…