BigDecimal 概述
Java 在 java.math 包中提供的 API 类 BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量 double 可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用 Float 和 Double 处理,但是 Double.valueOf(String) 和 Float.valueOf(String) 会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用 BigDecimal 类来操作。BigDecimal 所创建的是对象,故我们不能使用传统的 +、-、* 、/ 等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是 BigDecimal 的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
BigDecimal 常用构造函数
常用构造函数
BigDecimal(int):创建一个具有参数所指定整数值的对象。BigDecimal(double):创建一个具有参数所指定双精度值的对象。BigDecimal(long):创建一个具有参数所指定长整数值的对象。BigDecimal(String):创建一个具有参数所指定以字符串表示的数值的对象。
使用问题分析
使用示例:
1 | BigDecimal a =new BigDecimal(0.1); |
结果示例:
1 | a values is:0.1000000000000000055511151231257827021181583404541015625 |
原因分析:
-
参数类型为 double 的构造方法的结果有一定的不可预知性。有人可能认为在 Java 中写入
newBigDecimal(0.1)所创建的 BigDecimal 正好等于 0.1(非标度值1,其标度为1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于0.1(虽然表面上等于该值)。 -
String 构造方法是完全可预知的:写入
newBigDecimal("0.1")将创建一个 BigDecimal,它正好等于预期的0.1。因此,比较而言,通常建议优先使用 String 构造方法。 -
当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用
Double.toString(double)方法,然后使用BigDecimal(String)构造方法,将 double 转换为 String。要获取该结果,请使用static valueOf(double)方法。
BigDecimal 常用方法详解
常用方法
add(BigDecimal):BigDecimal 对象中的值相加,返回 BigDecimal 对象。subtract(BigDecimal):BigDecimal 对象中的值相减,返回 BigDecimal 对象。multiply(BigDecimal):BigDecimal 对象中的值相乘,返回 BigDecimal 对象。divide(BigDecimal):BigDecimal 对象中的值相除,返回 BigDecimal 对象。toString():将 BigDecimal 对象中的值转换成字符串。doubleValue():将 BigDecimal 对象中的值转换成双精度数。floatValue():将 BigDecimal 对象中的值转换成单精度数。longValue():将 BigDecimal 对象中的值转换成长整数。intValue():将 BigDecimal 对象中的值转换成整数。
BigDecimal 大小比较
java 中对 BigDecimal 比较大小一般用的是 bigdemical 的 compareTo 方法。
1 | int a = bigdemical.compareTo(bigdemical2); |
返回结果分析:
1 | a = -1, 表示 bigdemical 小于 bigdemical2; |
举例:a大于等于b
1 | new bigdemica(a).compareTo(new bigdemical(b)) >= 0 |
BigDecimal 格式化
由于 NumberFormat 类的 format() 方法可以使用 BigDecimal 对象作为其参数,可以利用 BigDecimal 对超出16位有效数字的货币值,百分值,以及一般数值进行格式化控制。以利用 BigDecimal 对货币和百分比格式化为例。首先,创建 BigDecimal 对象,进行 BigDecimal 的算术运算后,分别建立对货币和百分比格式化的引用,最后利用 BigDecimal 对象作为 format() 方法的参数,输出其格式化的货币值和百分比。
1 | NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用 |
结果:
1 | 贷款金额: ¥15,000.48 利率: 0.8% 利息: ¥120.00 |
BigDecimal 格式化保留2为小数,不足则补0:
1 | public class NumberFormat { |
结果为:
1 | 3.44 |
BigDecimal 常见异常
除法的时候出现异常
1 | java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result |
原因分析:通过 BigDecimal 的 divide 方法进行除法时当不整除,出现无限循环小数时,就会抛异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
解决方法:divide 方法设置精确的小数点,如:divide(xxxxx,2)
BigDecimal 总结
总结
在需要精确的小数计算时再使用 BigDecimal,BigDecimal 的性能比 double 和 float 差,在处理庞大,复杂的运算时尤为明显。故一般精度的计算没必要使用 BigDecimal。尽量使用参数类型为 String 的构造函数。BigDecimal 都是不可变的(immutable)的,在进行每一次四则运算时,都会产生一个新的对象,所以在做加减乘除运算时要记得要保存操作后的值。
工具类推荐
1 | package com.vivo.ars.util; |
参考:https://mp.weixin.qq.com/s/iywInXHcLL-ODNWPuGKV5Q
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !