1. 程式人生 > >可改進的BigDecimal的幾種用法

可改進的BigDecimal的幾種用法

我在實際專案中發現現存的程式碼中對BigDecimal的使用有些可以改進的地方,在此記錄下來,供大家參考。

 

1、new BigDecimal(0)、new BigDecimal("0")、new BigDecimal(1)、new BigDecimal("1")、new BigDecimal(10)、new BigDecimal("10")

BigInteger 和 BigDecimal 這兩個高精度數字類,對應整數 0、1、10 的值都有對應的常量(BigInteger.ZERO / BigDecimal.ZERO、BigInteger.ONE / BigDecimal.ONE、BigInteger.TEN / BigDecimal.TEN)可供使用。

為了節省建立物件和垃圾回收的開銷,我們應該直接使用這些常量。尤其是 new BigDecimal("0") 這種用法,它不僅會帶來建立 BigDecimal 物件的開銷,還有把字串解析成數字的開銷。

ZERO、ONE、TEN 這 3 個常量的值是不會變的,因為跟 Integer、Long 這些實現 Number 介面的類一樣,BigInteger 和 BigDecimal 也是不可變的(immutable),也就是說呼叫一個 BigDecimal 物件的任何公共的成員方法都不會改變該 BigDecimal 物件的值。執行如 BigDecimal.TEN.multiply(new BigDecimal(15)) 這樣的程式碼不會改變 BigDecimal.TEN 的值。

 

2、BigDecimal.ZERO.subtract(bigDecimal)

取一個 BigDecimal 變數的相反數,我們可以直接使用 BigDecimal 類的 negate 方法。

BigDecimal 類的核心其實是3個私有的成員屬性:一個 BigInteger 屬性 value 表示數字的各個位、一個整數屬性 scale 表示小數點的位置、一個整數屬性 sign 表示數字的符號(-1 表示負數、0 表示 0、1 表示正數)。一個 BigDecimal 物件的值就是 sign * value / (10 ^ scale)。例如 value 屬性的值為 15、scale 屬性的值為 0、sign 屬性的值為 -1,則該 BigDecimal 物件表示 -15;如果 value 屬性的值為 15、scale 屬性的值為 1、sign 屬性的值為 1,則該BigDecimal物件表示 15 / 10 = 1.5;如果 BigInteger 屬性的值為 15、小數點屬性的值為 -1、符號屬性的值為 1,則該 BigDecimal 物件表示 15 * 10 = 150。

negate 方法是呼叫 BigDecimal 的私有構造方法,直接建立一個 sign 屬性為原 BigDecimal 物件的 sign 的相反數的新的 BigDecimal 物件,不會涉及到減法運算的邏輯。如果我們使用 BigDecimal.ZERO 的 subtract 方法,則會帶來高精度小數減法的開銷(BigDecimal 的 subtract 方法需要先判斷兩個 BigDecimal 物件的 scale 屬性的大小,調整其中一個 BigDecimal 物件的 scale 屬性和 value 屬性使兩個 BigDecimal 物件的 scale 屬性相等)。

 

3、bigDecimal.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO.subtract(bigDecimal) : bigDecimal

取一個 BigDecimal 變數的絕對值,我們可以直接使用 BigDecimal 類的 abs 方法。

上文已提到,BigDecimal 類的值由 value、scale 和 sign 3個私有成員屬性決定。abs 方法是呼叫 BigDecimal 的私有構造方法,直接建立一個 sign 屬性為 1 的新的 BigDecimal 物件,可以為我們省去判斷一個 BigDecimal 物件的值是否小於 0 的開銷。

 

4、bigDecimal.multiply(new BigDecimal(100))、bigDecimal.divide(new BigDecimal(100))

要得到一個 BigDecimal 變數乘以 10 的整數次冪,我們可以直接使用 BigDecimal 類的 scaleByPowerOfTen 方法。

bigDecimal.scaleByPowerOfTen(n) 返回一個值為 bigDecimal * 10 ^ n 的新的 BigDecimal 物件。scaleByPowerOfTen 方法是呼叫 BigDecimal 的私有構造方法,直接建立一個 scale 屬性等於原 BigDecimal 物件的 scale - n 的新的 BigDecimal 物件,可以為我們省去高精度小數乘除法的開銷。

 

要全面深入瞭解 BigDecimal 的用法,可參考 JavaSE 8 的 API 文件OpenJDK 8 中 BigDecimal.java 的原始碼