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服务,因此不用担心连…

[html] 打印页面时怎样自定义打印页眉页脚或者去掉眉页脚?

[html] 打印页面时怎样自定义打印页眉页脚或者去掉眉页脚&#xff1f; <style type"text/css" media"print"> page { size: auto; /* auto is the initial value / margin: 0mm; / this affects the margin in the printer settings */ } </styl…

sqlite 的几点见解

这几天接触了sqlite数据库&#xff0c;开始不上手感觉太变态连DataTime数据类型的都不能返回一个DataSet。 但是在网上查了几天后才发现其实sqlite还是很容易上手的。 我说几点我预到的问题&#xff1a; 1&#xff0c;字段的自增我们在sqlite中的字段自增是把数据类型设为integ…

python正则匹配字符串中的数字_Python正则表达式匹配字符串中的数字

1.使用“\d”匹配全数字代码&#xff1a;import rezen "Arizona 479, 501, 870. Carlifornia 209, 213, 650."m re.findall("\d", zen)print(m)结果&#xff1a;[479, 501, 870, 209, 213, 650]但是上述这种方式也会引入非纯数据&#xff0c;例子如下&am…

node.js之文件读写模块,配合递归函数遍历文件夹和其中的文件

fs.stat会返回文件夹会文件的属性var fs require(fs); var wenwa function (pathname,callback) {fs.stat(pathname,function (err,data) {if(err) throw err;else{if(data.isDirectory()){var wenheichouwa function (callback){fs.readdir(pathname,function (err,fileor…

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

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

[html] 如何设置打印尺寸?

[html] 如何设置打印尺寸&#xff1f; media print { ... }个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

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

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

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

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

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

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

[html] 如何设置打印尺寸?

[html] 如何设置打印尺寸&#xff1f; 用一个单独的Css文件设置打印样式个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

db2 建库

建库 CREATE DATABASE TS1AUTOMATIC STORAGE NO --是否自动存储ON D:\ --路径ALIAS testUSING CODESET GBK --设置编码TERRITORY CN COLLATE --设置地域USING SYSTEM PAGESIZE 4096 --设置数据页大小(4kb 8kb 16kb 32kb)WITH aa --注释 建表----------------------------------…

python读取扫描形成的pdf_Python利用PyPDF2库获取PDF文件总页码实例

Python中可以利用PyPDF2库来获取该pdf文件的总页码&#xff0c;可以根据下面的方法一步步进行下去&#xff1a;1、首先&#xff0c;要安装PyPDF2库&#xff0c;利用以下命令即可&#xff1a;pip install PyPDF22、接着&#xff0c;就是直接编写代码了&#xff0c;其中我新建了一…

Apache实验-目录别名

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

python123第三周测验答案_python123 测验3: 基本数据类型 (第3周)

1.‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬# pow(x, 0.5)能够计算x的平方根&#xff0c;计算负数的平方根将产生&#xff1a;‪‬‪‬‪‬‪‬‪…

[html] 说下你对组件、模块、元素的理解,它们的区别在哪里?

[html] 说下你对组件、模块、元素的理解&#xff0c;它们的区别在哪里&#xff1f; 元素&#xff1a;元素是网页的一部分&#xff0c;在 XML 和 HTML 中&#xff0c;一个元素可以包含一个数据详情或者是一块文本或者是一张照片&#xff0c;亦或是什么也不包含。 一个典型的元素…

python中spark有什么功能_Spark SQL是什么,提供的主要功能有哪三种?

Spark SQL允许大家在Python、Java以及Scala中使用数据帧;利用多种结构化格式读取并写入数据;通过SQL进行大数据查询。Spark SQL属于Spark用于处理结构化与半结构化数据的接口。结构化数据是指那些拥有一定模式的数据&#xff0c;包括JSON、Hive Tables以及Parquet。模式意味着每…

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

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

Apache的虚拟主机

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