最近工作中接觸到了 Java BigDecimal類,准備整理一下用到的幾個常用方法。
簡介
Java在java.math包中提供的API類BigDecimal,用來對超過16位有效位的數進行精確的運算。雙精度浮點型變量double可以處理16位有效數。在實際應用中,需要對更大或者更小的數進行運算和處理。float和double只能用來做科學計算或者是工程計算,在商業計算中要用java.math.BigDecimal。BigDecimal所創建的是對象,我們不能使用傳統的+、-、*、/等算術運算符直接對其對象進行數學運算,而必須調用其相對應的方法。方法中的參數也必須是BigDecimal的對象。構造器是類的特殊方法,專門用來創建對象,特別是帶有參數的對象。
構造器
BigDecimal(int) 創建一個具有參數所指定整數值的對象。 BigDecimal(double) 創建一個具有參數所指定雙精度值的對象。 BigDecimal(long) 創建一個具有參數所指定長整數值的對象。 BigDecimal(String) 創建一個具有參數所指定以字符串表示的數值的對象。
這幾個都是常用的構造器,他們返回的對象都是BigDecimal對象。換而言之, 將各個類型的值轉換為BigDecimal對象,就是通過構造器。
反過來說,將BigDecimal對象轉換為其他類型的對象,我們通過以下幾種:
toString() 將BigDecimal對象的數值轉換成字符串。
doubleValue() 將BigDecimal對象中的值以雙精度數返回。
floatValue() 將BigDecimal對象中的值以單精度數返回。
longValue() 將BigDecimal對象中的值以長整數返回。
intValue() 將BigDecimal對象中的值以整數返回。
常用方法
BigDecimal b1 = new BigDecimal("20"); BigDecimal b2 = new BigDecimal("30"); b1.add(b2) :加法,求兩個BigDecimal類型數據的和。 b1.subtract(b2):減法,求兩個BigDecimal類型數據的差。 b1.multiply(b2):乘法,求兩個BigDecimal類型數據的積。 b1.remainder(b2):求余數,求b1除以b2的余數。 b1.max(b2) : 最大數,求兩個BigDecimal類型數據的最大值 b1.min(b2) : 最小數,求兩個BigDecimal類型數據的最小值。 bi.abs():絕對值,求BigDecimal類型數據的絕對值。 b1.negate():相反數,求BigDecimal類型數據的相反數。
這里把除法單獨拉出來
BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
除法 divide有三個參數的方法,第一參數表示除數,第二個參數表示小數點后保留位數,第三個參數表示取舍規則。只有在作除法運算或四舍五入時才用到取舍規則。 因為BigDecimal除法可能出現不能整除的情況,比如 4.5/1.3,這時會報錯java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result。所以當我們用三參數的除法方法時,規定了保留幾位小數以及你的保留方式,就可以避免異常。
幾個取舍規則:
ROUND_CEILING //向正無窮方向舍入 ROUND_DOWN //向零方向舍入 ROUND_FLOOR //向負無窮方向舍入 ROUND_HALF_DOWN //向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向下舍入, 例如1.55 保留一位小數結果為1.5 ROUND_HALF_EVEN //向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,如果保留位數是奇數,使用ROUND_HALF_UP,如果是偶數,使用ROUND_HALF_DOWN ROUND_HALF_UP //向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向上舍入, 1.55保留一位小數結果為1.6 ROUND_UNNECESSARY //計算結果是精確的,不需要舍入模式 ROUND_UP //向遠離0的方向舍入
我們最常用的四舍五入應該是 ROUND_HALF_UP
Note that this is the rounding mode that most of us were taught in grade school.
源碼中的注釋也解釋了這一點。
這里說下除法里的第三個參數,
a.divide(b,2,RoundingMode.HALF_UP)
這里RoundingMode其實是個枚舉類,點進去源碼可以看到其實他就是匹配到幾種取舍規則
UP(BigDecimal.ROUND_UP),
DOWN(BigDecimal.ROUND_DOWN),
CEILING(BigDecimal.ROUND_CEILING),
FLOOR(BigDecimal.ROUND_FLOOR),
HALF_UP(BigDecimal.ROUND_HALF_UP),
HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),
HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),
UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);
而最常用的就是 HALF_UP 也就是四舍五入。
那如果我們在乘法或者加法減法中也要保留幾位或者四舍五入,該怎么操作呢?
四舍五入
BigDecimal中有一個setScale()方法
第一個參數就是你要保留幾位,第二個可填的參數就是取舍規則,圖中的兩種殊途同歸。
如果你第二個參數不加,僅僅想保留幾位,他在源碼中會自動幫你選擇默認的規則。
public BigDecimal setScale(int newScale) { return setScale(newScale, ROUND_UNNECESSARY); } /** * Rounding mode to assert that the requested operation has an exact * result, hence no rounding is necessary. If this rounding mode is * specified on an operation that yields an inexact result, an * {@code ArithmeticException} is thrown. */ public final static int ROUND_UNNECESSARY = 7;
源碼中提及,當我們需要精確結果的時候,可以用這種取舍方式,但是如果你的結果不精確就會拋出異常。
栗子:
BigDecimal b1 = new BigDecimal("3.5"); BigDecimal b2 = new BigDecimal("7.7"); b1.divide(b2).setScale(2); Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. at java.math.BigDecimal.divide(BigDecimal.java:1690)
