目录
为什么要用BigDecimal ?
商业计算中,货币类或者小数点运算涉及到精度问题,BigDecimal解决高精度问题,保证数值正确。 对比float/double更偏向工程及科学运算,二进制浮点运算,在更广的数值上得到近似计算规律,但是涉及到钱等则需要准确的结果,故使用BigDecimal。
构造BigDecimal
BigDecimal(int)、BigDecimal(double)、BigDecimal(long)、BigDecimal(String)
创建一个整型/双精度/长整型/字符串数字初始值
一般使用BigDecimal(String)来初始化值,因为BigDecimal(double)无法控制精度
BigDecimal a = new BigDecimal("0.01");
加减乘除
均创建新的对象而非在原来基础上改变数值
加法add
BigDecimal a = new BigDecimal("0.01");
BigDecimal b = new BigDecimal("0.02");
BigDecimal result = a.add(b);
减法subtract
BigDecimal a = new BigDecimal("0.01");
BigDecimal b = new BigDecimal("0.02");
BigDecimal result = a.subtract(b); //结果为-0.01
乘法multiply
BigDecimal a = new BigDecimal("0.01");
BigDecimal b = new BigDecimal("0.02");
BigDecimal result = a.multiply(b);
除法divide
BigDecimal a = new BigDecimal("0.01");
BigDecimal b = new BigDecimal("0.02");
BigDecimal result = a.divide(b);
当分母为0,报错 java.lang.ArithmeticException: Division by zero
格式化
舍入模式
通过setScale()方法设置保留位数策略
setScale(n,策略) n表示保留几位小数,策略为以下策略,选择保留位数后的处理方式,如常用的四舍五入。setScale(1)表示保留1位小数,不带策略
****************************
ROUND_UP 向上取整
ROUND_DOWN 向下取整
ROUND_HALF_UP 四舍五入 0.25 -》0.3
ROUND_HALF_DOWN 五舍六入
ROUND_FLOOR 负无穷
ROUND_CEILING 正无穷
ROUND_HALF_EVEN 银行家舎入法
ROUND_UNNECESSARY 不需要舎入
常用模式四舍五入
BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("0.055");
BigDecimal c =a.multiply(b).setScale(2,BigDecimal.ROUND_HALF_UP)
结果为0.06 保留两位采用=四舍五入模式
去除结尾多余的0
通过.stripTrailingZeros()可去除为结尾多余的0
如0.00 -》0,0.660000000000 -》 0.66
去除科学计数法
如果计算
的结果为整数,则BigDecimal会自动转为科学计数法 如
BigDecimal a = new BigDecimal("6");
BigDecimal b = new BigDecimal("10.00");
BigDecimal c =a.multiply(b).setScale(2,BigDecimal.ROUND_HALF_UP).stripTrailingZeros();
System.out.println(c.toString());
此时结果为6E+1
将toString()改为toPlainString()即可正常输出
结合NumberFormat的一些货币操作
NumberFormat数字格式化类
例子
BigDecimal a = new BigDecimal("0.005");
//输出格式¥+价格
NumberFormat curreny = NumberFormat.getCurrencyInstance();
//输出格式 百分比%
NumberFormat percent = NumberFormat.getPercentInstance();
//设置百分比小数点最多保留3位
percent.setMaximumFractionDigits(3);
System.out.println(curreny.format(a) + " " + percent.format(a));
//输出 ¥0.00 0.5%
curreny 为货币格式,此时0.001输出为0元,若0.015则或输出0.02(满足保留2位四舍五入)
percent 为百分比格式 percent.setMaximumFractionDigits(n)设置转换为百分比小数点向右移动n-1位置
如,设置n为3,则转换会将小数点向右移动2位置,如0.00005 -》 0.005%、0.5 -》50%
但当小数为6位数后如0.000005,都将转换为0%
NumberFormat和DecimalFormat
注意点:
两者均为线程不安全的类,多线程操作需要注意,可使用ThreadLocal为每个线程生成一个本地实例或者使用synchronized来进行同步。
区别:
NumberFormat和DecimalFormat数字相关格式。
DateFormat和SimpleDateFormat也文字日期相关格式。
四者均为Format子类。DecimalFormat为NumberFormat子类,用于处理十进制数字格式
NumberFormat使用
获得实例
Locale.getDefault() 表示使用系统默认地区
NumberFormat integerNumber = NumberFormat.getIntegerInstance(Locale.getDefault());
常用实例构造方法
getInstance、getNumberInstance 数字格式
getIntegerInstance整数格式
getCurrencyInstance货币格式
getPercentInstance百分比的格式