在数据库中存储金额的数据类型通常用的是 decimal(20,2)
在java中与之对应的数据类型并不是double,而是java.math.BigDecimal.

上例子:

@Test
    public void testBigDecimal(){
        double a = 0.03;
        double b = 0.02;
        System.out.println("两个 double 类型的数据相减:"+ (a-b));

		BigDecimal x = new BigDecimal("0.03");
        BigDecimal y = new BigDecimal("0.02");
        System.out.println("两个 BigDecimal 类型的数据相减:"+ x.subtract(y));
    }

输出结果为:

两个 double 类型的数据相减:0.009999999999999998
两个 BigDecimal 类型的数据相减:0.01

为什么会这样呢? 因为float和double都是浮点数, 都有取值范围, 都有精度范围. 浮点数与通常使用的小数不同, 使用中, 往往难以确定. 常见的问题是定义了一个浮点数, 经过一系列的计算, 它本来应该等于某个确定值, 但实际上并不是! 金额必须是完全精确的计算, 故不能使用double 或者 float, 而应该采用java.math.BigDecimal.

加减乘除运算

加减乘除使用了英文的加减乘除, 即add, substract, multiply和divide

@Test
    public void testBigDecimal1(){
        BigDecimal x = new BigDecimal("0.09");
        BigDecimal y = new BigDecimal("0.03");
        System.out.println("两个 BigDecimal 类型的数据相加:" + x.add(y));
        System.out.println("两个 BigDecimal 类型的数据相减:"+ x.subtract(y));
        System.out.println("两个 BigDecimal 类型的数据相乘:"+ x.multiply(y));
        System.out.println("两个 BigDecimal 类型的数据相除:"+ x.divide(y));
    }

输出结果为:

两个 BigDecimal 类型的数据相加:0.12
两个 BigDecimal 类型的数据相减:0.06
两个 BigDecimal 类型的数据相乘:0.0027
两个 BigDecimal 类型的数据相除:3

大小比较

不可以用 “>” 或 “<” 来比较大小
可以通过BigDecimal的compareTo方法来进行比较。
返回的结果是int类型,-1表示小于,0是等于,1是大于。

对于0, 可以使用BigDecimal.ZERO表示 即 BigDecimal.ZERO = 0

小数位数及四舍五入规则

在项目中, 涉及到税费的计算, 计算的结果可能是小数点后面十几位, 那么怎么进行结算呢? 这就需要四舍五入

@Test
    public void testBigDecimal2(){
        BigDecimal x = new BigDecimal("0.05523545654897545616513");
        System.out.println("保留小数点后 2 位,之后的位数删除:" + x.setScale(2,BigDecimal.ROUND_DOWN));
        System.out.println("保留小数点后 2 位,之后的位数进位:" + x.setScale(2,BigDecimal.ROUND_UP));
        System.out.println("保留小数点后 2 位,之后的位数四舍五入:" + x.setScale(2,BigDecimal.ROUND_HALF_UP));
    }

输出结果:

保留小数点后 2 位,之后的位数删除:0.05
保留小数点后 2 位,之后的位数进位:0.06
保留小数点后 2 位,之后的位数四舍五入:0.06

注意 new BigDecimal()的坑

尽量在构造方法里使用String类型的数据,而不要为了省事使用 double类型的数据

示例:

@Test
    public void testBigDecimal3(){
        System.out.println("double类型:" + new BigDecimal(0.99));
        System.out.println("String类型:" + new BigDecimal("0.99"));
        System.out.println("BigDecimal类型:" + BigDecimal.valueOf(0.99));
    }

输出结果:

double类型:0.9899999999999999911182158029987476766109466552734375
String类型:0.99
BigDecimal类型:0.99

总结:
如果使用new BigDecimal()时,尽可能转换为String,或者直接使用BigDecimal.valueof(double)