if(a.compareTo(b) == -1){
System.out.println("a小于b");
}
if(a.compareTo(b) == 0){
System.out.println("a等于b");
}
if(a.compareTo(b) == 1){
System.out.println("a大于b");
}
if(a.compareTo(b) > -1){
System.out.println("a大于等于b");
}
if(a.compareTo(b) < 1){
System.out.println("a小于等于b");
}
查看compareTo源码发现并无异常处理机制,所以a,b都不可为空,异常需提前处理。
基础运算:
//加减乘除:
BigDecimal a= new BigDecimal("10");
BigDecimal b= new BigDecimal("5");
//加法
a.add(b);
//减法
a.subtract(b);
//乘法
a.multiply(b);
//除法
a.divide(b);
setScale(2) // 表示保留两位小数,默认用四舍五入方式
setScale(2,BigDecimal.ROUND_DOWN) // 向下取整
setScale(2,BigDecimal.ROUND_UP) // 向上取整
setScale(2,BigDecimal.ROUND_HALF_UP) // 四舍五入
setScaler(2,BigDecimal.ROUND_HALF_DOWN) // 四舍五入,如果是5则向下舍
常见错误:
1、BigDecial的所有操作都会生成一个新的对象:
amount.add( thisAmount ); // 错误
amount = amount.add( thisAmount ); // 正确
2、不要用equals方法来比较BigDecimal对象,因为它的equals方法会比较scale,如果scale不一样,它会返回false;
例如:
BigDecimal a = new BigDecimal("1.00");
BigDecimal b = new BigDecimal("1.0");
print(a.equals(b)); // false
3、如果直接使用a.divide(b)除法,有时会报除不尽异常,如下:
BigDecimal a = new BigDecimal(10);
BigDecimal b = new BigDecimal(3);
a = a.divide(b); // 错误会报如下异常:java.lang.ArithmeticException: Non-terminating
decimal expansion; no exact representable decimal result.
long num = 100000000123l;
BigDecimal totalFee = new BigDecimal(num);
BigDecimal d100 = new BigDecimal(100);
BigDecimal fee = totalFee.divide(d100,2,2);//小数点2位
System.out.println(fee);
总结
对于Long的比较,不要用等号,规律太多,根本记不住。而equals方法是非常安全的,可以放心用equals进行相等的比较。
对于BigDecimal的比较,不用用 == 也不要用equals,规律太多,根本记不住,而应该用compareTo方法。
4.3 四则运算
BigDecimal 提供了以下四则运算的方法:
add ——加法
subtract ——减法
divide ——除法,有可能除不尽,必须显式声明保留小数位数避免抛出ArithmeticException异常
multiply ——乘法
@Test
public void whenPerformingArithmetic_thenExpectedResult() {
BigDecimal bd1 = new BigDecimal("4.0");
BigDecimal bd2 = new BigDecimal("2.0");
BigDecimal sum = bd1.add(bd2);
BigDecimal difference = bd1.subtract(bd2);
BigDecimal quotient = bd1.divide(bd2);
BigDecimal product = bd1.multiply(bd2);
assertTrue(sum.compareTo(new BigDecimal("6.0")) == 0);
assertTrue(difference.compareTo(new BigDecimal("2.0")) == 0);
assertTrue(quotient.compareTo(new BigDecimal("2.0")) == 0);
assertTrue(product.compareTo(new BigDecimal("8.0")) == 0);
}
4.4 四舍五入
既然是数学运算就不得不讲四舍五入。比如我们在金额计算中很容易遇到最终结算金额为人民币22.355的情况。因为货币没有比分更低的单位所以我们要使用精度和舍入模式规则对数字进行剪裁。java提供有两个类控制舍入行为RoundingMode和MathContext 。MathContext执行的是IEEE 754R标准目前不太明白其使用场景,我们使用的比较多的是枚举RoundingMode。它提供了八种模式:
RoundingMode.UP:以小数位为原点 是正数取右边,负数取左边
RoundingMode.DOWN:以小数位为原点 也就是正数取左边,负数取右边
RoundingMode.FLOOR:取左边最近的正数
RoundingMode.CEILING:取右边最近的整数
RoundingMode.HALF_DOWN:五舍六入,负数先取绝对值再五舍六入再负数
RoundingMode.HALF_UP:四舍五入,负数原理同上
RoundingMode.HALF_EVEN:这个比较绕,整数位若是奇数则四舍五入,若是偶数则五舍六入
RoundingMode.ROUND_UNNECESSARY:不需要取整,如果存在小数位,就抛ArithmeticException 异常
- 格式化
数字格式化可通过操作类java.text.NumberFormat和java.text.DecimalFormat提供的api进行操作。其实我们只需要使用java.text.DecimalFormat,因为它代理了NumberFormat。我们来看一下它们的api:
5.1 NumberFormat
getInstance(Locale)、getNumberInstance(Locale)。返回指定语言环境的通用数值格式。
NumberFormat.getCurrencyInstance(Locale)。 返回指定语言环境的货币格式。
NumberFormat.getPercentInstance(Locale)。 返回指定语言环境的百分比格式。
NumberFormat.getIntegerInstance(Locale)。 返回指定语言环境的整数数值格式。
NumberFormat.setMinimumIntegerDigits(int)。设置数的整数部分所允许的最小位数。
NumberFormat.setMaximumIntegerDigits(int)。设置数的整数部分所允许的最大位数。
NumberFormat.setMinimumFractionDigits(int)。设置最少小数点位数,不足的位数以0补位,超出的话按实际位数输出。
NumberFormat.setMaximumFractionDigits(int)。设置最多保留小数位数,不足不补0。
5.2 DecimalFormat
DecimalFormat除了能代理上面的NumberFormat以外,还提供了基于pattern字符串的格式化风格,有点类似格式化时间一样。我们来看看pattern的规则:
“0”——表示一位数值,如没有,显示0。如“0000.0000”,整数位或小数位>4,按实际输出,<4整数位前面补0小数位后面补0,凑足4位。
“#”——表示任意位数的整数。如没有,则不显示。在小数点位使用,只表示一位小数,超出部分四舍五入。如:“#”:无小数,小数部分四舍五入。“.#”:整数部分不变,一位小数,四舍五入。“.##”:整数部分不变,二位小数,四舍五入。
“.”——表示小数点。注意一个pattern中只能出现一次,超过一次将格式化异常。
“,”——与模式“0”一起使用,表示逗号。注意一定不能在小数点后用,否则格式化异常。