一、BigDecimal格式化
由于NumberFormat類的format()方法可以使用BigDecimal物件作為其引數,可以利用BigDecimal對超出16位有效數字的貨幣值,百分值,以及一般數值進行格式化控制,
以利用BigDecimal對貨幣和百分比格式化為例,首先,創建BigDecimal物件,進行BigDecimal的算術運算后,分別建立對貨幣和百分比格式化的參考,最后利用BigDecimal物件作為format()方法的引數,輸出其格式化的貨幣值和百分比,
@Test
public void test8(){
NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立貨幣格式化參考
NumberFormat percent = NumberFormat.getPercentInstance(); //建立百分比格式化參考
percent.setMaximumFractionDigits(3); //百分比小數點最多3位
BigDecimal money = new BigDecimal("15000.48"); // 合同金額
BigDecimal taxRate = new BigDecimal("0.008"); // 稅率
BigDecimal taxRateMoney = money.multiply(taxRate); // 利息
System.out.println("合同金額: " + currency.format(money));
System.out.println("稅率: " + percent.format(taxRate));
System.out.println("利息: " + currency.format(taxRateMoney));
}
結果:

BigDecimal格式化保留2為小數,不足則補0:
@Test
public void test9(){
System.out.println(formatToNumber(new BigDecimal("3.435")));
System.out.println(formatToNumber(new BigDecimal(0)));
System.out.println(formatToNumber(new BigDecimal("0.00")));
System.out.println(formatToNumber(new BigDecimal("0.001")));
System.out.println(formatToNumber(new BigDecimal("0.006")));
System.out.println(formatToNumber(new BigDecimal("0.206")));
}
/**
* @desc 1.0~1之間的BigDecimal小數,格式化后失去前面的0,則前面直接加上0,
* 2.傳入的引數等于0,則直接回傳字串"0.00"
* 3.大于1的小數,直接格式化回傳字串
* @param obj 傳入的小數
* @return
*/
public static String formatToNumber(BigDecimal obj) {
DecimalFormat df = new DecimalFormat("#.00");
if(obj.compareTo(BigDecimal.ZERO)==0) {
return "0.00";
}else if(obj.compareTo(BigDecimal.ZERO)>0&&obj.compareTo(new BigDecimal(1))<0){
return "0"+df.format(obj).toString();
}else {
return df.format(obj).toString();
}
}
結果為:

二、BigDecimal常見例外
2.1、除法divide() 出現例外
使用除法函式在divide的時候要設定各種引數,要有除數、精確的小數位數和舍入模式,不然會出現報錯,原始碼如下:
注意這個BigDecimal的divide方法有兩個多載的方法,一個是傳兩個引數的,一個是傳三個引數的:
兩個引數的方法:
@param divisor value by which this {@code BigDecimal} is to be divided. 傳入除數
@param roundingMode rounding mode to apply. 傳入round的模式

三個引數的方法:
@param divisor value by which this {@code BigDecimal} is to be divided. 傳入除數
@param scale scale of the {@code BigDecimal} quotient to be returned. 傳入精度
@param roundingMode rounding mode to apply. 傳入round的模式

代碼演示:
@Test
public void test10(){
BigDecimal Dividend = new BigDecimal("1");
BigDecimal divisor = new BigDecimal("3");
BigDecimal res1 = Dividend.divide(divisor,3,BigDecimal.ROUND_UP);
System.out.println("除法ROUND_UP:"+res1);
BigDecimal res2 = Dividend.divide(divisor,3,BigDecimal.ROUND_DOWN);
System.out.println("除法ROUND_DOWN:"+res2);
BigDecimal res3 = Dividend.divide(divisor,3,BigDecimal.ROUND_CEILING);
System.out.println("除法ROUND_CEILING:"+res3);
BigDecimal res4 = Dividend.divide(divisor,3,BigDecimal.ROUND_FLOOR);
System.out.println("除法ROUND_FLOOR:"+res4);
BigDecimal res5 = Dividend.divide(divisor,3,BigDecimal.ROUND_HALF_UP);
System.out.println("除法ROUND_HALF_UP:"+res5);
BigDecimal res6 = Dividend.divide(divisor,3,BigDecimal.ROUND_HALF_DOWN);
System.out.println("除法ROUND_HALF_DOWN:"+res6);
BigDecimal res7 = Dividend.divide(divisor,3,BigDecimal.ROUND_HALF_EVEN);
System.out.println("除法ROUND_HALF_EVEN:"+res7);
BigDecimal res8 = Dividend.divide(divisor,3,BigDecimal.ROUND_UNNECESSARY);
System.out.println("除法ROUND_UNNECESSARY:"+res8);
}
結果展示:


原因分析:
斷言請求的操作具有精確的結果,因此不需要舍入,如果對獲得精確結果的操作指定此舍入模式,則拋出ArithmeticException,
2.2、除法divide() 出現例外
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result
原因分析:
原來JAVA中如果用BigDecimal做除法的時候一定要在divide方法中傳遞第二個引數,定義精確到小數點后幾位,否則在不整除的情況下,結果是無限回圈小數時,就會拋出以下例外,java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
解決方法:
a.divide(b, 2, BigDecimal.ROUND_HALF_UP);
三、BigDecimal的八種舍入模式
@Test
public void test11(){
BigDecimal a = new BigDecimal("1.12345");
System.out.println("a = " + a);
BigDecimal b = a.setScale(4,BigDecimal.ROUND_HALF_DOWN);
System.out.println("b = " + b);
BigDecimal c = a.setScale(4,BigDecimal.ROUND_HALF_UP);
System.out.println("c = " + c);
}


3.1、ROUND_UP
舍入遠離零的舍入模式(向遠離0的方向舍入),
在丟棄非零部分之前始終增加數字(始終對非零舍棄部分前面的數字加1),
注意,此舍入模式始終不會減少計算值的大小,
3.2、ROUND_DOWN
接近零的舍入模式(向零方向舍入),
在丟棄某部分之前始終不增加數字(從不對舍棄部分前面的數字加1,即截短),
注意,此舍入模式始終不會增加計算值的大小,
3.3、ROUND_CEILING
接近正無窮大的舍入模式(向正無窮方向舍入),
如果 BigDecimal 為正,則舍入行為與 ROUND_UP 相同;
如果為負,則舍入行為與 ROUND_DOWN 相同,
注意,此舍入模式始終不會減少計算值,
3.4、ROUND_FLOOR
接近負無窮大的舍入模式(向負無窮方向舍入),
如果 BigDecimal 為正,則舍入行為與 ROUND_DOWN 相同;
如果為負,則舍入行為與 ROUND_UP 相同,
注意,此舍入模式始終不會增加計算值,
3.5、ROUND_HALF_UP
向“最接近的”數字舍入,如果與兩個相鄰數字的距離相等,則為向上舍入的舍入模式(向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向上舍入, 1.55保留一位小數結果為1.6),
如果舍棄部分 >= 0.5,則舍入行為與 ROUND_UP 相同;否則舍入行為與 ROUND_DOWN 相同,
注意,這是我們大多數人在小學時就學過的舍入模式(四舍五入),
3.6、ROUND_HALF_DOWN
向“最接近的”數字舍入,如果與兩個相鄰數字的距離相等,則為上舍入的舍入模式
(向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向下舍入, 例如1.55 保留一位小數結果為1.5),
如果舍棄部分 > 0.5,則舍入行為與 ROUND_UP 相同;否則舍入行為與 ROUND_DOWN 相同(五舍六入),
3.7、ROUND_HALF_EVEN
向“最接近的”數字舍入,如果與兩個相鄰數字的距離相等,則向相鄰的偶數舍入,
如果舍棄部分左邊的數字為奇數,則舍入行為與 ROUND_HALF_UP 相同;
如果為偶數,則舍入行為與 ROUND_HALF_DOWN 相同
(向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,如果保留位數是奇數,使用ROUND_HALF_UP ,如果是偶數,使用ROUND_HALF_DOWN),
注意,在重復進行一系列計算時,此舍入模式可以將累加錯誤減到最小,
此舍入模式也稱為“銀行家舍入法”,主要在美國使用,四舍六入,五分兩種情況,
如果前一位為奇數,則入位,否則舍去,
以下例子為保留小數點1位,那么這種舍入方式下的結果,
1.15>1.2 1.25>1.2
3.8、ROUND_UNNECESSARY
斷言請求的操作具有精確的結果,因此不需要舍入(計算結果是精確的,不需要舍入模式),
如果對獲得精確結果的操作指定此舍入模式,則拋出ArithmeticException,
四、BigDecimal總結
4.1、總結
- 在需要精確的小數計算時再使用BigDecimal,BigDecimal的性能比double和float差,在處理龐大,復雜的運算時尤為明顯,故一般精度的計算沒必要使用BigDecimal,
- 盡量使用引數型別為String的建構式,
- BigDecimal都是不可變的(immutable)的, 在進行每一次四則運算時,都會產生一個新的物件 ,所以在做加減乘除運算時要記得要保存操作后的值,
4.2、工具類推薦
ArithmeticUtils
五、請關注后續博客
記得點波收藏o!!!
博客首頁:https://www.cnblogs.com/liyhbk/
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/187023.html
標籤:其他
