前言:BigDecimal的产生背景
在Java的8种基本类型中,我们知道double和float基本数据类型存在着精度缺失问题。我们先来看一个例子。
double augend = 1.0000001; double addend = 0.0000001; double sum = augend + addend; //sum: 1.0000002000000001 System.out.println("sum: " + sum);
可以看到sum并不是我们所想要的1.0000002,而是1.0000002000000001。虽然误差非常小,但是如果开发银行金融类产品时,我们就需要绝对精确的数据。试想下这样一个场景,在一个用户余额为99.95元时,恰好他要购买总价99.95元的商品,而程序中定义总价时使用了double类型,这就有可能使得总价大于余额,导致用户无法购买商品。不过,Java提供了BigDecimal类用来了解决此类问题。
一. 如何使用BigDecimal
本文将从一个实际生活场景出发——超市购物,通过在买单时计算总消费金额来介绍BigDecimal的基本使用方法(加减乘除等)。由这个生活中的具体例子出发,加深我们对BigDecimal的记忆和理解。
1.1 初始化BigDecimal对象
BigDecimal的源码中有16个构造函数和3个静态方法可以用于初始化BigDecimal对象。如图所示:
本文会重点介绍上图所标记的三种方法。我们先建立一个Receipt类,在该类中定义四个常量并使用main方法将它们打印出来。
从控制台的输出结果中,我们可以看到使用参数类型为String类型的构造函数创建的MEATPRICE对象打印结果为19.98,而使用参数类型为double类型的构造函数创建的RICEPRICE对象打印结果为3.3300000000000000710542735760100185871124267578125(每个机器可能不一样)。当我们的数量足够多的时候,就会产生导致总价产生较大的误差,这是我们不希望看到的。同时,在使用静态方法valueOf的时候,也能得到精确的数字。这是因为源码中调用了Double类型的toString方法,然后再调用了参数类型为String类型的构造函数创建该对象。
1.2 BigDecimal的加减乘除等实例方法
在进行下面的操作之前,我们将RICE_PRICE改为使用valueOf方法初始化。我们在main方法中定义了double类型的weightOfMeat、weightOfRice变量和in