BigDecimal的个人总结

前言:
互联网公司,对于BigDecimal的使用,还是较为频繁的,那么就会涉及到关于这个类型的种种问题.

1:为什么使用BigDecimal
首先java八大基本类型真的很基本,4个整型搞不了小数,double和float搞的了小数,但搞不好,关键时刻就调链子,当然这也和他们存储方式有关(二进制无法精确的表示1/10),天生注定搞不了精密计算,尤其是和钱相关的.

所以一般我们对于精密点的计算和涉及货币的计算,都会使用BigDecimal.他的出现,就是为了解决基本数据类型浮点数不能进行精确计算的问题.

2:如何使用BigDecimal
就说最常用的:
2.1.初始化,一般使用这个构造方法:new BigDecimal(String value);
其他的不再多说,某度很多,只能说我们一般都会用这个String类型的入参

关于BigDecimal的初始化,有一个坑要注意,就是尽量使用String类型的去初始化。
不信的话,可以看看下面的例子:BigDecimal a = new BigDecimal(1.01);BigDecimal b = new BigDecimal(1.02);BigDecimal c = new BigDecimal("1.01");BigDecimal d = new BigDecimal("1.02");System.out.println(a.add(b));System.out.println(c.add(d));
最终的打印结果是:
2.0300000000000000266453525910037569701671600341796875
2.03
很明显,也是精度问题。这块要注意。

2.2.基本运算

add(BigDecimal)            BigDecimal对象中的值相加,然后返回这个对象。
subtract(BigDecimal)       BigDecimal对象中的值相减,然后返回这个对象。
multiply(BigDecimal)       BigDecimal对象中的值相乘,然后返回这个对象。
divide(BigDecimal)         BigDecimal对象中的值相除,然后返回这个对象。
toString()                 将BigDecimal对象中的值以字符串形式返回。
doubleValue()              将BigDecimal对象中的值以双精度数返回。
floatValue()               将BigDecimal对象中的值以单精度数返回。
longValue()                将BigDecimal对象中的值以长整数返回。
intValue()                 将BigDecimal对象中的值以整数返回。

3.采坑经验(敲黑板的重点!!!)
3.1.将BigDecimal类性的值(10.1000)传给页面后,页面展示的(10.1000)不是我们想要的(10.1),该怎么处理?

    BigDecimal money;public BigDecimal getMoney() {return money;}最开始上面的这种处理方式,如果money是10.1000,那么get方法也会拿到10.1000,但其实我们想要的是10.1就好了.
-------------------------------------------------------------------------    那怎么办,直接上最终版(重写个getMoneyString方法):public String getMoneyString() {return money.stripTrailingZeros().toPlainString();}这个方法返回的,就是10.1,String类型的
--------------------------------------------------------------------------解释下:1.stripTrailingZeros()方法官方文档对返回的解释是:a numerically equal BigDecimal with any trailing zeros removed.而且从方法名就可以看出来,就是去掉末尾的0.那么,为什么还要用toPlainString()方法呢?看个例子:new BigDecimal("60000.000").stripTrailingZeros();这个结果是6E+4,而不是我们想要的60000,而且官方文档上也说明了,返回的值,会用科学计数法来表示,所以看下个方法2.toPlainString()官方文档对返回的解释是:a string representation of this BigDecimal without an exponent field.就是返回一个不用指数表示的字符串形式的值.所以两个方法连用,就可以达到对BigDecimal的初步控制.

3.2.值的比较用compareTo,不要用equals
compareTo:左边比右边数大,返回1,相等返回0,比右边小返回-1
equals:BigDecimal重写了equals,比较的是数值

3.3.除法要养成习惯去设置精度,以免出现无限循环的小数而抛异常
(java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result)

new BigDecimal("10").divide(new BigDecimal("3"));
这个就会抛出上面的异常.所以要用下面的new BigDecimal("10").divide(new BigDecimal("3"), 4,        BigDecimal.ROUND_HALF_DOWN);
这个代表10除以3,结果保留4位小数,采用四舍五入保留
所以结果就是:3.3333

3.4.既然用了BigDecimal了,就应避免再与浮点类型互相转换,否则精度会受很大的影响

4.BigDecimal格式化
可以使用NumberFormat类的format(BigDecimal)方法,利用NumberFormat不同类型的实例,对BigDecimal转换不同的格式.详细可以查查NumberFormat的各种实例方法,比如:
NumberFormat.getCurrencyInstance();
NumberFormat.getCurrencyInstance();
NumberFormat.getInstance();

根据不同的需求,使用不同的格式…
下面提供两个现成的转换精度的方法

/**** @param obj 传入的BigDecimal类型* @return 返回String类型,保留两位小数(四舍五入),不够补0*/public static String formatToStringWithTwoPlaces(BigDecimal obj) {DecimalFormat df = new DecimalFormat("#.00");if (obj.compareTo(BigDecimal.ZERO) == 0) {return "0.00";} else if (obj.compareTo(BigDecimal.ZERO) > 0 && obj.compareTo(new BigDecimal(1)) < 0) {return "0" + df.format(obj).toString();} else {return df.format(obj).toString();}}//这个方法效果和上一个一样,两种不同的实现罢了public static String getDecimalStr(BigDecimal bd) {String bdStr;if (bd != null) {bdStr = bd.setScale(2, RoundingMode.HALF_EVEN).toPlainString();} else {bdStr = "0.00";}return bdStr;}public static void main(String[] args) {//各种类型测试BigDecimal bigDecimal1 = new BigDecimal("0");System.out.println(formatToStringWithTwoPlaces(bigDecimal1));//0.00BigDecimal bigDecimal11 = new BigDecimal("0.6");System.out.println(formatToStringWithTwoPlaces(bigDecimal11));//0.60BigDecimal bigDecimal12 = new BigDecimal("0.6666");System.out.println(formatToStringWithTwoPlaces(bigDecimal12));//0.67BigDecimal bigDecimal2 = new BigDecimal("2");System.out.println(formatToStringWithTwoPlaces(bigDecimal2));//2.00BigDecimal bigDecimal3 = new BigDecimal("2.1");System.out.println(formatToStringWithTwoPlaces(bigDecimal3));//2.10BigDecimal bigDecimal4 = new BigDecimal("2.22");System.out.println(formatToStringWithTwoPlaces(bigDecimal4));//2.22BigDecimal bigDecimal5 = new BigDecimal("2.333");System.out.println(formatToStringWithTwoPlaces(bigDecimal5));//2.33BigDecimal bigDecimal15 = new BigDecimal("0");System.out.println(getDecimalStr(bigDecimal15));//0.00BigDecimal bigDecimal115 = new BigDecimal("0.6");System.out.println(getDecimalStr(bigDecimal115));//0.60BigDecimal bigDecimal125 = new BigDecimal("0.6666");System.out.println(ConvertUtil.getDecimalStr(bigDecimal125));//0.67BigDecimal bigDecimal25 = new BigDecimal("2");System.out.println(getDecimalStr(bigDecimal25));//2.00BigDecimal bigDecimal35 = new BigDecimal("2.1");System.out.println(getDecimalStr(bigDecimal35));//2.10BigDecimal bigDecimal45 = new BigDecimal("2.22");System.out.println(getDecimalStr(bigDecimal45));//2.22BigDecimal bigDecimal55 = new BigDecimal("2.333");System.out.println(getDecimalStr(bigDecimal55));//2.33}

5.BigDecimal取整

    public static void main(String[] args) {BigDecimal bigDecimal = new BigDecimal(6.66);//6.66除以6,向上取整,结果为2BigDecimal divide = bigDecimal.divide(BigDecimal.valueOf(6),0, BigDecimal.ROUND_UP);System.out.println(divide);//2//6.66除以6,不报错,但有这么多小数跟在后面BigDecimal divide2 = bigDecimal.divide(BigDecimal.valueOf(6), BigDecimal.ROUND_UP);System.out.println(divide2);//1.110000000000000023684757858670006195704142252605//1.110000000000000023684757858670006195704142252605向上取整,结果为2BigDecimal bigDecimal1 = divide2.setScale(0, BigDecimal.ROUND_UP);System.out.println(bigDecimal1);//6.66除以6,报错:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.BigDecimal divide1 = bigDecimal.divide(BigDecimal.valueOf(6));System.out.println(divide1);//报错}

各个roundingMode详解如下:
ROUND_UP:非0时,舍弃小数后(整数部分)加1,比如1.11结果为2,-1.11结果为 -2
ROUND_DOWN:直接舍弃小数
ROUND_CEILING:如果 BigDecimal 是正的,则做 ROUND_UP 操作;如果为负,则做 ROUND_DOWN 操作 (一句话:取附近较大的整数)
ROUND_FLOOR: 如果 BigDecimal 是正的,则做 ROUND_DOWN 操作;如果为负,则做 ROUND_UP 操作(一句话:取附近较小的整数)
ROUND_HALF_UP:四舍五入(取更近的整数)
ROUND_HALF_DOWN:跟ROUND_HALF_UP 差别仅在于0.5时会向下取整
ROUND_HALF_EVEN:取最近的偶数
ROUND_UNNECESSARY:不需要取整,如果存在小数位,就抛ArithmeticException 异常

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

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

相关文章

MagicRecord For IOS API深层解析

一、NSManagedObjectContext创建和获取1.默认上下文(每种只存在一个)&#xff08;1&#xff09;MR_rootSavingContext&#xff1a;此方法返回的上下文类型为NSPrivateQueueConcurrencyType(后台线程)&#xff0c;直接关联持久化协调器&#xff0c;对此上下文对象执行保存方法&a…

BeanUtils.copyProperties(对象A,对象B)

对于两个实例的复制,如果属性名字相同,则可以通过这个方法来操作,但是在使用的时候,一定要注意BeanUtils用的是哪个包的,因为常用的两个包,都有这个类和对应的方法,而复制方向却相反,所以一定要注意自动导包时选择的包!!!!!! 1.import org.springframework.beans.BeanUtils 这…

Xcode中的-ObjC和-all_load

有时候使用第三方库的时候&#xff0c;需要在Xcode的Build Settings下Other Linker Flags里面加入-ObjC标志。 之所以使用该标志&#xff0c;和Objective-C的一个重要特性&#xff1a;类别&#xff08;category)有关。根据这里的解释&#xff0c;Unix的标准静态库实现和Object…

[前台]---ajax返回200成功,却进入error函数的解决方法

最近碰到一个问题,就是如题目所说,ajax在调用的时候,明明返回成功了,但js代码却走到了error中,最后发现是我返回的json格式不对,jQuery在1.4后,对ajax返回的json格式有了很强的限制,所以一定要用严格的JSON格式返回. 先上代码: jQuery.ajax({type: "POST",async: tr…

SpringMVC解决静态资源不能访问

解决: 直接在SpringMVC的xml文件中加一行配置: <mvc:default-servlet-handler/> 问题根源: 做项目迁移的时候,原来控制层的框架是Struts2,现在要换成SpringMVC,第一版是尽量少改动的移过去,保证功能都正常,第二版开始优化,于是: 原来项目的访问都是XXX.action,现在想…

CocoaPods版本升级

和往常一样使用CocoaPods管理一个基于FMDB的项目类库 命令行执行 $ pod install [!] The master repo requires CocoaPods 0.32.1 - 失败&#xff0c;提示需要CocoaPods 0.32.1版本 查看CocoaPods版本 $ pod --version 0.29.0 确实需要更新了 命令行更新&#xff08;安装&…

[前台]---js获取input标签中name相同的各个value值

在页面form表单中,经常会有相同name的多个input标签,在提交表单前需要对这些input的value值做校验,就要在js中拿到这些值,下面这个方法,亲测是最实在的: 页面:<input type"hidden" name"myname" value"aa"/><input type"hidden&qu…

Objective-C消息转发

我们要通过一个小例子来简单、通俗的理解一下什么是消息转发以及如何消息转发&#xff0c;希望看完这篇文章时大家会彻底的明白OC的消息。首先&#xff0c;你需要知道这两个概念&#xff1a; OC中调用方法就是向对象发送消息。 比如 &#xff1a; 1[person run];这实际上这是在…

[前台]---js中方法的强制返回和java中方法的强制返回

java写惯了,偶尔写个js,真是各种坑,比如方法中的return的效果就不一样: java中: public static void main(String[] args) {String[] a {"1","2","3"};for (String s : a) {if(s.equals("1")){System.out.println(s);return;//方法中…

Create groups 与 Create folder references的区别

选择了Create groups方式添加了一个文件&#xff0c;我们会发现被添加进来的文件&#xff0c;文件夹是黄色的。选择了 Create folder references方式添加进来的文件的文件夹是蓝色的。那么两种方式有什么区别呢&#xff1f; 1.使用Create groups 为任何新增加的文件夹创建组&a…

[前台]---js重复上传一张图片两次,第二次失败的解决办法和思路

js重复上传一张图片两次,第二次会失败,解决办法就是修改input的value值. 先上代码: <input style"display:none" type"file" id"aaa" onchange"newuploadImageForDetail(event)" accept"image/jpg, image/jpeg, image/gif, …

XMPP协议简介

XMPP是一种基于标准通用标记语言的子集XML的协议&#xff0c;它继承了在XML环境中灵活的发展性。因此&#xff0c;基于XMPP的应用具有超强的可扩展性。经过扩展以后的XMPP可以通过发送扩展的信息来处理用户的需求&#xff0c;以及在XMPP的顶端建立如内容发布系统和基于地址的服…

[前台]---关于input标签的value值

碰到这个情况,先上代码: <input type"hidden" id"input-shoppingListType" value0/> 这样写的话,最终在获取value的值的时候,平时都是0,直到有一次成了’0/’,发现了吗?把后面的斜杠也给拿到了,最终导致报错了 结果: <input type"hidde…

布尔类型(boolean/Boolean)自动生成的get方法需要注意的小细节

idea会自动生成get/set方法的, 对于布尔类型,要非常注意生成的get方法,到底是is开头还是get开头. 先说结论: 1.Boolean类型,生成的get方法是get开头的(建议使用这个). 2.boolean类型,生成的get方法是is开头的(用这个最好重写getXxx()格式的方法). 以下这个例子,可以验证这…

[前台]---js中去掉双引号或者单引号

在js中有这么一种情况,就是需要在function中动态的给标签加属性值,这时候如果带有引号,可能会导致加的属性值不是想要的,这时只需要去掉引号就可以,建议用下面这个: var a "双引号字符串"; a a.replace("\"","").replace("\"&q…

XMPP扩展协议详解

基本的jabber客户端必须实现以下标准协议&#xff08;XEP-0211&#xff09; 1、RFC3920 Core http://tools.ietf.org/html/rfc3920 2、RFC3921 Instant Messaging and Presence http://tools.ietf.org/html/rfc3921 3、XEP-030 Service Discovery http://www.xmpp.org/extensio…

[前台]---图片上传和校验

记一次简单的图片上传验证: 页面:<input type"file" id"hiddenFile" onchange"uploadImage(event)" accept"image/jpg, image/jpeg, image/gif, image/png">立即上传图片js: function uploadImage(e) {//图片的提前校验,如果返…

FMDB简介

FMDB在SQLite基础上封装。 FMDB会在编译的时候知道你是用的ARC还是MRC&#xff0c;然后进行相应处理。使用方法一、FMDB有三个主要的类1.FMDatabase – 表示一个单独的SQLite数据库。 用来执行SQLite的命令。2.FMResultSet – 表示FMDatabase执行查询后结果集3.FMDatabaseQueue…

[前台]---js+jquery校验姓名,手机号,身份证号

记一次前台验证姓名,手机号,身份证号的代码,复制即用,前提是有引入jquery. var name "姓名"if(!is_forbidName(name)){alert("姓名有误!");}var phone "18888888888";var validateTel /^1[23456789]\d{9}/;if(!validateTel.test(phone)){aler…

React Native新手引导

序言 本教程希望让您快速熟悉使用React Native来编写iOS和Android App的技巧。如果你希望知道React Native是什么以及为什么Facebook打造了它&#xff0c;可以读读这篇博文 我们这里假设你已经有了使用React编写Web应用程序的经验。如果还没有&#xff0c;建议你可以先从React官…